Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #82600 > unrolled thread

Has "stack overflow" specified behavior?

Started bywij <wyniijj@gmail.com>
First post2021-12-12 00:42 -0800
Last post2021-12-14 01:41 -0800
Articles 19 on this page of 59 — 20 participants

Back to article view | Back to comp.lang.c++


Contents

  Has "stack overflow" specified behavior? wij <wyniijj@gmail.com> - 2021-12-12 00:42 -0800
    Re: Has "stack overflow" specified behavior? Bonita Montero <Bonita.Montero@gmail.com> - 2021-12-12 09:52 +0100
      Re: Has "stack overflow" specified behavior? red floyd <no.spam.here@its.invalid> - 2021-12-12 12:59 -0800
    Re: Has "stack overflow" specified behavior? Paavo Helde <eesnimi@osa.pri.ee> - 2021-12-13 01:51 +0200
      Re: Has "stack overflow" specified behavior? Juha Nieminen <nospam@thanks.invalid> - 2021-12-13 05:48 +0000
        Re: Has "stack overflow" specified behavior? Bo Persson <bo@bo-persson.se> - 2021-12-13 10:44 +0100
          Re: Has "stack overflow" specified behavior? wij <wyniijj@gmail.com> - 2021-12-13 04:44 -0800
          Re: Has "stack overflow" specified behavior? Richard Damon <Richard@Damon-Family.org> - 2021-12-13 07:47 -0500
            Re: Has "stack overflow" specified behavior? Bonita Montero <Bonita.Montero@gmail.com> - 2021-12-14 08:32 +0100
              Re: Has "stack overflow" specified behavior? Richard Damon <Richard@Damon-Family.org> - 2021-12-14 07:49 -0500
                Re: Has "stack overflow" specified behavior? scott@slp53.sl.home (Scott Lurndal) - 2021-12-14 14:23 +0000
                Re: Has "stack overflow" specified behavior? "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2021-12-14 16:16 +0100
          Re: Has "stack overflow" specified behavior? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-13 12:13 -0500
            Re: Has "stack overflow" specified behavior? Öö Tiib <ootiib@hot.ee> - 2021-12-13 12:05 -0800
              Re: Has "stack overflow" specified behavior? "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2021-12-13 17:11 -0800
              Re: Has "stack overflow" specified behavior? "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2021-12-13 19:00 -0800
                Re: Has "stack overflow" specified behavior? Öö Tiib <ootiib@hot.ee> - 2021-12-13 23:03 -0800
            Re: Has "stack overflow" specified behavior? Bonita Montero <Bonita.Montero@gmail.com> - 2021-12-14 08:33 +0100
              Re: Has "stack overflow" specified behavior? David Brown <david.brown@hesbynett.no> - 2021-12-14 09:13 +0100
                Re: Has "stack overflow" specified behavior? Juha Nieminen <nospam@thanks.invalid> - 2021-12-14 10:09 +0000
                  Re: Has "stack overflow" specified behavior? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-14 16:14 +0000
                    Re: Has "stack overflow" specified behavior? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-12-14 15:23 -0800
                Re: Has "stack overflow" specified behavior? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-14 16:10 +0000
                Re: Has "stack overflow" specified behavior? Bonita Montero <Bonita.Montero@gmail.com> - 2021-12-14 17:38 +0100
                  Re: Has "stack overflow" specified behavior? scott@slp53.sl.home (Scott Lurndal) - 2021-12-14 17:09 +0000
                    Re: Has "stack overflow" specified behavior? Bonita Montero <Bonita.Montero@gmail.com> - 2021-12-14 18:39 +0100
                    Re: Has "stack overflow" specified behavior? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-14 11:01 -0800
                Re: Has "stack overflow" specified behavior? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-14 10:52 -0800
                  Re: Has "stack overflow" specified behavior? David Brown <david.brown@hesbynett.no> - 2021-12-14 20:15 +0100
              Re: Has "stack overflow" specified behavior? Richard Damon <Richard@Damon-Family.org> - 2021-12-14 07:59 -0500
            Re: Has "stack overflow" specified behavior? "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2021-12-14 16:19 +0100
              Re: Has "stack overflow" specified behavior? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-14 11:33 -0500
        Re: Has "stack overflow" specified behavior? Manfred <noname@add.invalid> - 2021-12-13 17:23 +0100
        Re: Has "stack overflow" specified behavior? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2021-12-15 23:27 +0000
          Re: Has "stack overflow" specified behavior? David Brown <david.brown@hesbynett.no> - 2021-12-16 08:37 +0100
      Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-13 14:16 -0800
        Re: Has "stack overflow" specified behavior? wij <wyniijj@gmail.com> - 2021-12-13 15:07 -0800
          Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-16 05:53 -0800
            Re: Has "stack overflow" specified behavior? wij <wyniijj@gmail.com> - 2021-12-16 08:34 -0800
              Re: Has "stack overflow" specified behavior? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-16 12:17 -0800
                Re: Has "stack overflow" specified behavior? wij <wyniijj@gmail.com> - 2021-12-16 13:38 -0800
                  Re: Has "stack overflow" specified behavior? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-16 14:15 -0800
              Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-16 20:10 -0800
            Re: Has "stack overflow" specified behavior? Öö Tiib <ootiib@hot.ee> - 2021-12-16 14:14 -0800
              Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-16 20:20 -0800
                Re: Has "stack overflow" specified behavior? Öö Tiib <ootiib@hot.ee> - 2021-12-17 08:46 -0800
        Re: Has "stack overflow" specified behavior? Paavo Helde <eesnimi@osa.pri.ee> - 2021-12-14 10:32 +0200
          Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-16 07:42 -0800
            Re: Has "stack overflow" specified behavior? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2021-12-17 01:07 +0000
              Re: Has "stack overflow" specified behavior? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-17 01:28 +0000
              Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-16 19:54 -0800
                Re: Has "stack overflow" specified behavior? Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2021-12-17 10:06 +0000
    Re: Has "stack overflow" specified behavior? Manfred <noname@add.invalid> - 2021-12-13 17:08 +0100
      Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-13 13:50 -0800
        Re: Has "stack overflow" specified behavior? Manfred <noname@add.invalid> - 2021-12-14 16:32 +0100
    Re: Has "stack overflow" specified behavior? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-12-13 13:13 -0800
    Re: Has "stack overflow" specified behavior? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-13 15:55 -0800
      Re: Has "stack overflow" specified behavior? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-13 15:58 -0800
      Re: Has "stack overflow" specified behavior? wij <wyniijj@gmail.com> - 2021-12-14 01:41 -0800

Page 3 of 3 — ← Prev page 1 2 [3]


#82665

Fromwij <wyniijj@gmail.com>
Date2021-12-16 13:38 -0800
Message-ID<f7ba174b-4d99-4bdf-a1c4-cc024d1f50acn@googlegroups.com>
In reply to#82663
On Friday, 17 December 2021 at 04:17:31 UTC+8, Keith Thompson wrote:
> wij <wyn...@gmail.com> writes: 
> [...]
> > By the way, I though the 'stack' still must exist no matter how it is 
> > implemented. Because the process of RAII/function call and the 
> > 'auto' (old name) variables are mostly efficient in the stack. 
> > These all added to be most efficient in one stack (or 'primary stack').
> It depends on what you mean by "stack". 
> 
> Most C++ implementations use a "stack" in the sense of a contiguous 
> region of memory managed via a pointer to the "top". 
> 
> A contiguous memory "stack" (which is not required by the standard) is 
> the most common way to implement the abstract last-in first-out 
> semantics of function calls. There are implementations (at least for C, 
> and probably for C++) that do something similar to a malloc call to 
> allocate storage for a new function call.
> -- 
> Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com 
> Working, but not speaking, for Philips 
> void Void(void) { Void(); } /* The recursive call of the void */

If so, something should still be remained in the main stack for the tracking
to work. Each function can have its own stack, that stack can be reallocated,
but the address value can't change. In all, these maneuvers are opaque to the user.
The user code just don't assume the amount of stack space acquired is the whole
thing. Nothing too significantly changes from the user's point of view. IOW, getting
the amount of stack space (from API) seems still significant, just not common.

[toc] | [prev] | [next] | [standalone]


#82667

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-12-16 14:15 -0800
Message-ID<871r2c8ad1.fsf@nosuchdomain.example.com>
In reply to#82665
wij <wyniijj@gmail.com> writes:
> On Friday, 17 December 2021 at 04:17:31 UTC+8, Keith Thompson wrote:
>> wij <wyn...@gmail.com> writes: 
>> [...]
>> > By the way, I though the 'stack' still must exist no matter how it is 
>> > implemented. Because the process of RAII/function call and the 
>> > 'auto' (old name) variables are mostly efficient in the stack. 
>> > These all added to be most efficient in one stack (or 'primary stack').
>> It depends on what you mean by "stack". 
>> 
>> Most C++ implementations use a "stack" in the sense of a contiguous 
>> region of memory managed via a pointer to the "top". 
>> 
>> A contiguous memory "stack" (which is not required by the standard) is 
>> the most common way to implement the abstract last-in first-out 
>> semantics of function calls. There are implementations (at least for C, 
>> and probably for C++) that do something similar to a malloc call to 
>> allocate storage for a new function call.
>
> If so, something should still be remained in the main stack for the
> tracking to work. Each function can have its own stack, that stack can
> be reallocated, but the address value can't change. In all, these
> maneuvers are opaque to the user.  The user code just don't assume the
> amount of stack space acquired is the whole thing. Nothing too
> significantly changes from the user's point of view. IOW, getting the
> amount of stack space (from API) seems still significant, just not
> common.

As I said, there are (at least) two very different meanings of the word
"stack".  I can't tell which one you're using here.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#82673

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-12-16 20:10 -0800
Message-ID<86k0g33m80.fsf@linuxsc.com>
In reply to#82662
wij <wyniijj@gmail.com> writes:

[...]

> By the way, I though the 'stack' still must exist no matter how it
> is implemented.  [...]

Some sort of machinery with stack-like behavior must be there, to
support recursive calls if nothing else.  But there doesn't have
to be a "stack" in the sense of a fixed, contiguous region of
memory that is used exclusively for state local to each call of a
function.  Other ways of providing function-local state have been
used, and depending on the operating environment they can be
practical, feasible, or even preferable.

[toc] | [prev] | [next] | [standalone]


#82666

FromÖö Tiib <ootiib@hot.ee>
Date2021-12-16 14:14 -0800
Message-ID<ae763530-9753-4bc5-940c-c1a8db528c55n@googlegroups.com>
In reply to#82657
On Thursday, 16 December 2021 at 15:53:48 UTC+2, Tim Rentsch wrote:
> 
> 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. 

Lack of capability of operations that provide storage to fail does
not follow from abstract machine being abstract. 
The very same abstract machine has malloc function that can
fail to provide storage. About malloc we also have no
concern where the memory might come from so that is utterly
orthogonal point.  

[toc] | [prev] | [next] | [standalone]


#82674

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-12-16 20:20 -0800
Message-ID<86fsqr3lr7.fsf@linuxsc.com>
In reply to#82666
Tiib <ootiib@hot.ee> writes:

> On Thursday, 16 December 2021 at 15:53:48 UTC+2, Tim Rentsch wrote:
>
>> 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.
>
> Lack of capability of operations that provide storage to fail does
> not follow from abstract machine being abstract. [...]

Yes, that was poor phrasing on my part.  Because of the kinds of
semantic descriptions used in defining the abstract machine tend
to gloss over certain kinds of details, we may reasonably expect
that they don't take running out of memory into account.  And
that is indeed the case in the C++ standard for function calls
and what happens with local variables.  Section 6.9.1 paragraph 1
says this:

    An instance of each object with automatic storage duration
    (6.7.5.3) is associated with each entry into its block.  Such
    an object exists and retains its last-stored value during the
    execution of the block and while the block is suspended [...]

There is no mention of any possibility of running out of memory.

[toc] | [prev] | [next] | [standalone]


#82677

FromÖö Tiib <ootiib@hot.ee>
Date2021-12-17 08:46 -0800
Message-ID<7f699f7a-e91d-4f21-b9a8-71175f36a6edn@googlegroups.com>
In reply to#82674
On Friday, 17 December 2021 at 06:21:00 UTC+2, Tim Rentsch wrote:
> Tiib <oot...@hot.ee> writes: 
> 
> > On Thursday, 16 December 2021 at 15:53:48 UTC+2, Tim Rentsch wrote: 
> > 
> >> 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. 
> > 
> > Lack of capability of operations that provide storage to fail does
> > not follow from abstract machine being abstract. [...] 
> 
> Yes, that was poor phrasing on my part. Because of the kinds of 
> semantic descriptions used in defining the abstract machine tend 
> to gloss over certain kinds of details, we may reasonably expect 
> that they don't take running out of memory into account. And 
> that is indeed the case in the C++ standard for function calls 
> and what happens with local variables. Section 6.9.1 paragraph 1 
> says this: 
> 
> An instance of each object with automatic storage duration 
> (6.7.5.3) is associated with each entry into its block. Such 
> an object exists and retains its last-stored value during the 
> execution of the block and while the block is suspended [...] 
> 
> There is no mention of any possibility of running out of memory.

I agree. There are none defined ways for some operations like
 
char txt[100]{}; 

to fail because of lack of storage. Meanwhile somewhat equivalent 

std::string str(100, 0);

can fail because of lack of storage.  There std::allocator<char>
of that str can throw std::bad_alloc.
So IMHO  the first definition of txt could also be defined
to throw std::bad_alloc (or something special like 
std::stack_overflow) because of failing to complete.
That would not make the abstract machine less
abstract but just ... better designed.
 

[toc] | [prev] | [next] | [standalone]


#82624

FromPaavo Helde <eesnimi@osa.pri.ee>
Date2021-12-14 10:32 +0200
Message-ID<sp9kq1$iua$1@dont-email.me>
In reply to#82614
14.12.2021 00:16 Tim Rentsch kirjutas:
> Paavo Helde <eesnimi@osa.pri.ee> writes:
> 
>> 12.12.2021 10:42 wij kirjutas:
>>
>>> void t() {
>>>     int a;
>>>     ++a;
>>>     t();
>>> };
>>>
>>> int main()
>>> {
>>>    t();
>>> }
>>
>> 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.

You might be right in that after fixing the uninitialized memory reading 
bug the program would not contain UB. Nevertheless, the standard gives 
explicit permission to a C++ implementation to optimize away such code 
with no observable side effects, making this whole program a non-op 
instead of an infinite CPU or memory eater:

"6.9.2.2 Forward progress [intro.progress]
1 The implementation may assume that any thread will eventually do one 
of the following:
(1.1) — terminate,
(1.2) — make a call to a library I/O function,
(1.3) — perform an access through a volatile glvalue, or
(1.4) — perform a synchronization operation or an atomic operation.
[Note: This is intended to allow compiler transformations such as 
removal of empty loops, even when termination cannot be proven. —end note]"

[toc] | [prev] | [next] | [standalone]


#82659

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-12-16 07:42 -0800
Message-ID<865yro4kub.fsf@linuxsc.com>
In reply to#82624
Paavo Helde <eesnimi@osa.pri.ee> writes:

> 14.12.2021 00:16 Tim Rentsch kirjutas:
>
>> Paavo Helde <eesnimi@osa.pri.ee> writes:
>>
>>> 12.12.2021 10:42 wij kirjutas:
>>>
>>>> void t() {
>>>>     int a;
>>>>     ++a;
>>>>     t();
>>>> };
>>>>
>>>> int main()
>>>> {
>>>>    t();
>>>> }
>>>
>>> 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.
>
> You might be right in that after fixing the uninitialized memory
> reading bug the program would not contain UB.  Nevertheless, the
> standard gives explicit permission to a C++ implementation to optimize
> away such code with no observable side effects, making this whole
> program a non-op instead of an infinite CPU or memory eater:
>
> "6.9.2.2 Forward progress [intro.progress]
> 1 The implementation may assume that any thread will eventually do one
> of the following:
> (1.1) - terminate,
> (1.2) - make a call to a library I/O function,
> (1.3) - perform an access through a volatile glvalue, or
> (1.4) - perform a synchronization operation or an atomic operation.
> [Note:  This is intended to allow compiler transformations such as
> removal of empty loops, even when termination cannot be proven.  -end
> note]"

Yes, I noticed that before.  I didn't comment on it because, one,
it strikes me as incidental to the main question, and two, if we
change the example just slightly

    void t() {
        volatile int a = 0;
        ++a;
        t();
    };
    
    int main()
    {
       t();
    }

then the program cannot be optimized into nothingness, so we
still have the question of how an implementation is obliged to
treat this program.  And I think the answer is the same, that
implementations are obliged to try to carry it out faithfully but
are allowed to fail when they run out of memory.  Failure here
isn't the same as undefined behavior, because up to the point of
actually running out of memory everything is fine as far as the
abstract semantics are concerned.  To say that another way, it is
a well-established point that undefined behavior is allowed to
affect things "in the past", but here that freedom is not
granted.  The presence of volatile reads and writes means that
there are other consequences that could be observed, such as
program running time, so there isn't the same kind of freedom
as would be allowed for undefined behavior.

[toc] | [prev] | [next] | [standalone]


#82668

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2021-12-17 01:07 +0000
Message-ID<20211217010755.f1f69829e33365c39389e163@cvine--nospam--.freeserve.co.uk>
In reply to#82659
On Thu, 16 Dec 2021 07:42:52 -0800
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> Yes, I noticed that before.  I didn't comment on it because, one,
> it strikes me as incidental to the main question, and two, if we
> change the example just slightly
> 
>     void t() {
>         volatile int a = 0;
>         ++a;
>         t();
>     };
>     
>     int main()
>     {
>        t();
>     }
> 
> then the program cannot be optimized into nothingness, so we
> still have the question of how an implementation is obliged to
> treat this program.  And I think the answer is the same, that
> implementations are obliged to try to carry it out faithfully but
> are allowed to fail when they run out of memory.

Isn't overflow in signed integers still undefined behavior?  If so
implementations can do whatever they want should they implement tail
call optimization and so overflow on the integer.

[toc] | [prev] | [next] | [standalone]


#82669

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-12-17 01:28 +0000
Message-ID<87r1acrpd7.fsf@bsb.me.uk>
In reply to#82668
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> On Thu, 16 Dec 2021 07:42:52 -0800
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>> Yes, I noticed that before.  I didn't comment on it because, one,
>> it strikes me as incidental to the main question, and two, if we
>> change the example just slightly
>> 
>>     void t() {
>>         volatile int a = 0;
>>         ++a;
>>         t();
>>     };
>>     
>>     int main()
>>     {
>>        t();
>>     }
>> 
>> then the program cannot be optimized into nothingness, so we
>> still have the question of how an implementation is obliged to
>> treat this program.  And I think the answer is the same, that
>> implementations are obliged to try to carry it out faithfully but
>> are allowed to fail when they run out of memory.
>
> Isn't overflow in signed integers still undefined behavior?  If so
> implementations can do whatever they want should they implement tail
> call optimization and so overflow on the integer.

Optimising that tail call won't cause integer overflow.  Optimisations
are obliged to preserve semantics!

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#82672

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-12-16 19:54 -0800
Message-ID<86o85f3mza.fsf@linuxsc.com>
In reply to#82668
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> On Thu, 16 Dec 2021 07:42:52 -0800
> Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
>
>> Yes, I noticed that before.  I didn't comment on it because, one,
>> it strikes me as incidental to the main question, and two, if we
>> change the example just slightly
>>
>>     void t() {
>>         volatile int a = 0;
>>         ++a;
>>         t();
>>     };
>>
>>     int main()
>>     {
>>        t();
>>     }
>>
>> then the program cannot be optimized into nothingness, so we
>> still have the question of how an implementation is obliged to
>> treat this program.  And I think the answer is the same, that
>> implementations are obliged to try to carry it out faithfully but
>> are allowed to fail when they run out of memory.
>
> Isn't overflow in signed integers still undefined behavior?  If so
> implementations can do whatever they want should they implement tail
> call optimization and so overflow on the integer.

There is one 'a' variable for each level of recursion.  Each 'a'
starts at 0 and gets incremented to 1, stopping at that value
just before the recursive call.  So none of the 'a' variables
ever overflows.

[toc] | [prev] | [next] | [standalone]


#82676

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2021-12-17 10:06 +0000
Message-ID<20211217100623.f8bbb01b156ad9005bc9f2be@cvine--nospam--.freeserve.co.uk>
In reply to#82672
On Thu, 16 Dec 2021 19:54:17 -0800
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
> 
> > On Thu, 16 Dec 2021 07:42:52 -0800
> > Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
> >
> >> Yes, I noticed that before.  I didn't comment on it because, one,
> >> it strikes me as incidental to the main question, and two, if we
> >> change the example just slightly
> >>
> >>     void t() {
> >>         volatile int a = 0;
> >>         ++a;
> >>         t();
> >>     };
> >>
> >>     int main()
> >>     {
> >>        t();
> >>     }
> >>
> >> then the program cannot be optimized into nothingness, so we
> >> still have the question of how an implementation is obliged to
> >> treat this program.  And I think the answer is the same, that
> >> implementations are obliged to try to carry it out faithfully but
> >> are allowed to fail when they run out of memory.
> >
> > Isn't overflow in signed integers still undefined behavior?  If so
> > implementations can do whatever they want should they implement tail
> > call optimization and so overflow on the integer.
> 
> There is one 'a' variable for each level of recursion.  Each 'a'
> starts at 0 and gets incremented to 1, stopping at that value
> just before the recursive call.  So none of the 'a' variables
> ever overflows.

Good point!

[toc] | [prev] | [next] | [standalone]


#82608

FromManfred <noname@add.invalid>
Date2021-12-13 17:08 +0100
Message-ID<sp7r5m$1vdp$1@gioia.aioe.org>
In reply to#82600
On 12/12/2021 9:42 AM, wij wrote:
> void t() {
>    int a;
>    ++a;
>    t();
> };
> 
> int main()
> {
>   t();
> }
> 
> ---
> Has "stack overflow" specified behavior?

Putting apart the specific example, the standard describes the behavior 
of the abstract machine only, but Appendix B refers to constraints posed 
by actual implementations, and that includes the "nesting levels of 
compound statements" (which in turn include function bodies).
So, what you call stack overflow (an expression not found in the 
standard) is in fact a possible violation of a constraint posed by the 
implementation.
As a kind of constraint violation this leads to UB - specifically I'd 
consider this under n4860 p4.1 clause (2.3) "If a program contains a 
violation of a rule for which no diagnostic is required, this document 
places no requirement on implementations with respect to that program".

With respect to the example given, n4860 p6.9.2.2 gives explicit 
permission to an implementation to remove the loop, and compile the 
whole program as a no-op (ref. "observable behavior").

[toc] | [prev] | [next] | [standalone]


#82613

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-12-13 13:50 -0800
Message-ID<86h7bc5g48.fsf@linuxsc.com>
In reply to#82608
Manfred <noname@add.invalid> writes:

> On 12/12/2021 9:42 AM, wij wrote:
>
>> void t() {
>>    int a;
>>    ++a;
>>    t();
>> };
>>
>> int main()
>> {
>>   t();
>> }
>>
>> ---
>> Has "stack overflow" specified behavior?
>
> Putting apart the specific example, the standard describes the
> behavior of the abstract machine only, but Appendix B refers to
> constraints posed by actual implementations, and that includes the
> "nesting levels of compound statements" (which in turn include
> function bodies).
> So, what you call stack overflow (an expression not found in the
> standard) is in fact a possible violation of a constraint posed by the
> implementation.
> As a kind of constraint violation this leads to UB - specifically I'd
> consider this under n4860 p4.1 clause (2.3) "If a program contains a
> violation of a rule for which no diagnostic is required, this document
> places no requirement on implementations with respect to that
> program".

First, I think you mean Annex B, not Appendix B.

Second, Annex B never uses the word 'constraint'.

Third, Annex B is informative, not normative.  Nothing it says can
change the rules governing the C++ language.  (Side note: Annex B
itself says in the last sentence of paragraph 2:

    However, these quantities are only guidelines and do not
    determine compliance.

End side note.)

The program shown above (after fixing the problem of reading an
uninitialized variable) has defined behavior, not undefined
behavior.  An execution of the program in an actual machine may
fail due to running out of stack space (or any other resource)
per section 4.1 paragraph 2.1.  Despite that, what happens in the
abstract machine is well-defined, and so the program has only
defined behavior, and no undefined behavior.

[toc] | [prev] | [next] | [standalone]


#82632

FromManfred <noname@add.invalid>
Date2021-12-14 16:32 +0100
Message-ID<spade5$1mcs$1@gioia.aioe.org>
In reply to#82613
On 12/13/2021 10:50 PM, Tim Rentsch wrote:
> Manfred <noname@add.invalid> writes:
> 
>> On 12/12/2021 9:42 AM, wij wrote:
>>
>>> void t() {
>>>     int a;
>>>     ++a;
>>>     t();
>>> };
>>>
>>> int main()
>>> {
>>>    t();
>>> }
>>>
>>> ---
>>> Has "stack overflow" specified behavior?
>>
>> Putting apart the specific example, the standard describes the
>> behavior of the abstract machine only, but Appendix B refers to
>> constraints posed by actual implementations, and that includes the
>> "nesting levels of compound statements" (which in turn include
>> function bodies).
>> So, what you call stack overflow (an expression not found in the
>> standard) is in fact a possible violation of a constraint posed by the
>> implementation.
>> As a kind of constraint violation this leads to UB - specifically I'd
>> consider this under n4860 p4.1 clause (2.3) "If a program contains a
>> violation of a rule for which no diagnostic is required, this document
>> places no requirement on implementations with respect to that
>> program".
> 
> First, I think you mean Annex B, not Appendix B.

Yes, Annex B

> 
> Second, Annex B never uses the word 'constraint'.

Clause 2: "The limits may constrain quantities that include those 
described below or others"

> 
> Third, Annex B is informative, not normative.  Nothing it says can
> change the rules governing the C++ language.
It is informative because it cannot mandate constraints that are 
inherently implementation dependent: see the word "may" above. However, 
whenever such constraints are posed by the implementation (i.e. always 
for any real implementation) they are obviously effective.


   (Side note: Annex B
> itself says in the last sentence of paragraph 2:
> 
>      However, these quantities are only guidelines and do not
>      determine compliance.
> 
> End side note.)

The "guideline" part is about the list of constrained quantities. Any 
given physical implementation "may constrain quantities that include 
those described below or others", which obviously leaves implementations 
free choice of which limits they pose (and it couldn't be any different).

> 
> The program shown above (after fixing the problem of reading an
> uninitialized variable) has defined behavior, not undefined
> behavior.  An execution of the program in an actual machine may
> fail due to running out of stack space (or any other resource)
> per section 4.1 paragraph 2.1.  Despite that, what happens in the
> abstract machine is well-defined, and so the program has only
> defined behavior, and no undefined behavior.

I beg to differ.

[toc] | [prev] | [next] | [standalone]


#82612

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-12-13 13:13 -0800
Message-ID<86o85k5htl.fsf@linuxsc.com>
In reply to#82600
wij <wyniijj@gmail.com> writes:

> void t() {
>   int a;
>   ++a;
>   t();
> };
>
> int main()
> {
>  t();
> }
>
> ---
> Has "stack overflow" specified behavior?

The expression '++a' tries to read an uninitialized variable.
After correcting for that oversight (for example, by giving a
value to 'a' at its declaration by 'int a = 0;'), the program has
defined behavior.  To be more specific, each of the operations
asked for in the program has a well-defined description of what
is to happen in the abstract machine, which means the program as
a whole has defined behavior.

Note that this conclusion is about what will take place in the
/abstract/ machine, and not about what occurs if and when the
program is run in an /actual/ machine.  The C++ standard
explicitly lets executing a program in an actual machine off the
hook for running out of any kind of limited resource, including
but not limited to "stack space".  Section 4.1 paragraph 2.1 of
n4860 says this:

    If a program contains no violations of the rules in this
    document, a conforming implementation shall, within its
    resource limits, accept and correctly execute that program.

So even though the program has defined behavior, it may very
well fail due to running out of stack space when executed.
Moreover that applies to all programs, for any kind of
resource the implementation might depend on.

Short summary:  the program (not counting the uninitialized
access) has defined behavior, but may fail because of stack
overflow during an actual execution.

[toc] | [prev] | [next] | [standalone]


#82616

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-12-13 15:55 -0800
Message-ID<877dc89i1n.fsf@nosuchdomain.example.com>
In reply to#82600
wij <wyniijj@gmail.com> writes:
> void t() {
>   int a;
>   ++a;
>   t();
> };
>
> int main()
> {
>  t();
> }
>
> ---
> Has "stack overflow" specified behavior?

The standard does not specify what happens when a resource limit is
exceeded.  In my opinion that matches the standard's definition of
"undefined behavior" (behavior that is not defined).

Is the variable `a` intended to track the depth of the recursion?  It
doesn't.  A new instance of `a` is created every time t is called.  You
didn't initialize `a`, but if you initialized it to 0 then `++a` would
simply set it to 1.

If you made `a` static, it would count the depth of the recursion -- and
you'd have undefined behavior after the value of `a` reaches INT_MAX.

With `a` defined as you did here, there's a distinct instance of `a` for
each call to t, and each instance has its own distinct address, a value
of type int*.  There can be at most 2**(CHAR_BIT * sizeof (int*))
distinct int* values.  If you never refer to the value or address of `a`,
an optimizing compiler is likely to eliminate it and change the
recursive call to a loop, but that doesn't apply in the abstract
machine.  See N1570 5.1.2.3 "Program execution":

    The semantic descriptions in this International Standard describe
    the behavior of an abstract machine in which issues of optimization
    are irrelevant.

In the abstract machine, each instance of `a` occupies sizeof (int) bytes
and has a unique address of type int*.  After optimization, `a` might not
exist.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#82617

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-12-13 15:58 -0800
Message-ID<8735mw9hvy.fsf@nosuchdomain.example.com>
In reply to#82616
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> wij <wyniijj@gmail.com> writes:
>> void t() {
>>   int a;
>>   ++a;
>>   t();
>> };
>>
>> int main()
>> {
>>  t();
>> }
>>
>> ---
>> Has "stack overflow" specified behavior?
>
> The standard does not specify what happens when a resource limit is
> exceeded.  In my opinion that matches the standard's definition of
> "undefined behavior" (behavior that is not defined).
>
> Is the variable `a` intended to track the depth of the recursion?  It
> doesn't.  A new instance of `a` is created every time t is called.  You
> didn't initialize `a`, but if you initialized it to 0 then `++a` would
> simply set it to 1.
>
> If you made `a` static, it would count the depth of the recursion -- and
> you'd have undefined behavior after the value of `a` reaches INT_MAX.
>
> With `a` defined as you did here, there's a distinct instance of `a` for
> each call to t, and each instance has its own distinct address, a value
> of type int*.  There can be at most 2**(CHAR_BIT * sizeof (int*))
> distinct int* values.  If you never refer to the value or address of `a`,
> an optimizing compiler is likely to eliminate it and change the
> recursive call to a loop, but that doesn't apply in the abstract
> machine.  See N1570 5.1.2.3 "Program execution":
>
>     The semantic descriptions in this International Standard describe
>     the behavior of an abstract machine in which issues of optimization
>     are irrelevant.
>
> In the abstract machine, each instance of `a` occupies sizeof (int) bytes
> and has a unique address of type int*.  After optimization, `a` might not
> exist.

My apologiess, I didn't notice which newsgroup I was in and gave a C
answer.  But the C++ standard also discusses the "abstract machine" in
section 4.6 [intro.execution], with a very similar meaning.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#82625

Fromwij <wyniijj@gmail.com>
Date2021-12-14 01:41 -0800
Message-ID<f81bfa04-4b52-47fd-80ca-acd27bae0381n@googlegroups.com>
In reply to#82616
On Tuesday, 14 December 2021 at 07:55:35 UTC+8, Keith Thompson wrote:
> wij <wyn...@gmail.com> writes: 
> > void t() { 
> > int a; 
> > ++a; 
> > t(); 
> > }; 
> > 
> > int main() 
> > { 
> > t(); 
> > } 
> > 
> > --- 
> > Has "stack overflow" specified behavior?
> The standard does not specify what happens when a resource limit is 
> exceeded. In my opinion that matches the standard's definition of 
> "undefined behavior" (behavior that is not defined). 
> 
> Is the variable `a` intended to track the depth of the recursion? It 
> doesn't. A new instance of `a` is created every time t is called. You 
> didn't initialize `a`, but if you initialized it to 0 then `++a` would 
> simply set it to 1. 
> 
> If you made `a` static, it would count the depth of the recursion -- and 
> you'd have undefined behavior after the value of `a` reaches INT_MAX. 
> 
> With `a` defined as you did here, there's a distinct instance of `a` for 
> each call to t, and each instance has its own distinct address, a value 
> of type int*. There can be at most 2**(CHAR_BIT * sizeof (int*)) 
> distinct int* values. If you never refer to the value or address of `a`, 
> an optimizing compiler is likely to eliminate it and change the 
> recursive call to a loop, but that doesn't apply in the abstract 
> machine. See N1570 5.1.2.3 "Program execution": 
> 
> The semantic descriptions in this International Standard describe 
> the behavior of an abstract machine in which issues of optimization 
> are irrelevant. 
> 
> In the abstract machine, each instance of `a` occupies sizeof (int) bytes 
> and has a unique address of type int*. After optimization, `a` might not 
> exist. 
> 
> -- 
> Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com 
> Working, but not speaking, for Philips 
> void Void(void) { Void(); } /* The recursive call of the void */

The 'a' was added when typing to remove 'optimization' answer, not succeeded.
Sorry it caused too(?) many attention (but, answers to that part might be helpful
to other readers).

[toc] | [prev] | [standalone]


Page 3 of 3 — ← Prev page 1 2 [3]

Back to top | Article view | comp.lang.c++


csiph-web