wij <
wyn...@gmail.com> writes:
> On Tuesday, 14 December 2021 at 06:16:23 UTC+8, Tim Rentsch wrote:
>
>> Paavo Helde <
ees...@osa.pri.ee> writes:
>>
>>> 12.12.2021 10:42 wij kirjutas:
>>>
>>>> void t() {
>>>> int a;
>>>> ++a;
>>>> t();
>>>> };
>>>>
>>>> int main()
>>>> {
>>>> t();
>>>> }
>>>>
>>>> ---
>>>> Has "stack overflow" specified behavior?
>>>
>>> No. Stack overflow is arguably the least specified behavior of them
>>> all. The stack size is extremely limited (few MB), compared to the
>>> RAM amounts current computers have (tens of GB). There is no
>>> standard-defined way to detect stack overflow, not to speak about
>>> handling it. That's one reason why using stack-allocated things
>>> like std::array needs special care, especially when writing
>>> libraries (which need to execute in a stack of unknown size and
>>> fill-up).
>>>
>>> There are some implementation-defined ways though to survive stack
>>> overflows, but it's not so easy. You cannot continue the program if
>>> there is no more stack space, so the only way is to throw an
>>> exception. Alas, there is no "throw" statement in the code, so this
>>> would be an "asynchronous" exception appearing at a pretty random
>>> place in the code, meaning that the compiler must cope with such
>>> exceptions, which may easily slow down the whole program (witness
>>> the /EHa compiler option in MSVC).
>>>
>>> BTW, your example code is not guaranteed to cause stack overflow, it
>>> might go into an infinite loop instead because of tail recursion, or
>>> become a zero op by optimizing the whole t() function away, either
>>> as UB or as a code with no effect.
>>
>> It's important to distinguish the two realms of abstract machine
>> and actual machine. In the abstract machine, the program shown
>> above (after fixing the problem of reading an uninitialized
>> variable) does have a well-defined specification, and the program
>> as a whole has defined behavior. Whether a program has defined
>> behavior or undefined behavior is determined solely by what goes
>> on in the abstract machine (which may depend on values read from
>> a file or other input device, etc, but still the question is to
>> be answered considering only what happens in the abstract
>> machine, with reference to any actual machine). Everything the
>> program does has a well-defined specification, and so the program
>> has only defined behavior, and no undefined behavior.
>> In an actual machine, an implementation is obliged to carry out
>> the abstract semantics only to the extent that the execution
>> does not exceed the implementation's "resource limits", which
>> might be anything at all, including stack space. Once such a
>> resource limit is exceeded, the implementation has no further
>> obligations, and may abort, or whatever. But that isn't the
>> same as undefined behavior, which depends solely on what the
>> standard says about operations in the abstract machine.
>
> If the concept of abstract (ideal) machine is used (the 1st time I
> heard this term in use).
The term "abstract machine" comes from the C++ standard (and
originally from the C standard). It is not an ideal machine,
just an abstract machine, meaning there are some details it
doesn't pin down.
> The infinite recursive call should be defined as it is (never
> return, or infinite loop except semantics 'optimized' to differ),
> all functions within should be carried out successfully.
Because the abstract machine is abstract, it doesn't have any
notion of running out of memory. The semantic descriptions
simply say another object instance is created, without any
concern about where memory for that object might come from.
> But, for this ideal to be anything reasonable, there should at
> least one machine that can execute the program correctly.
Again, the abstract machine is only abstract, not ideal. Part of
the point of considering an abstract machine is the abstract
machine doesn't need to consider some things that actual machines
do. It isn't possible to make an actual machine that faithfully
models the abstract machine, in much the same way that it isn't
possible to make an actual machine that faithfully models a
Turing machine. Actual machines are always bounded; Turing
machines, and the abstract machine, are potentially unbounded.
> If this is accepted, what should this 'actual machine' do with the
> infinite recursive call?
The premise that there is some actual machine that faithfully
models the abstract machine is wrong. Since there is no such
actual machine, there is no answer to the question of what it
should do. Any "actual machine" that can in fact be made will
at some point just run out of memory.