Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #82600 > unrolled thread
| Started by | wij <wyniijj@gmail.com> |
|---|---|
| First post | 2021-12-12 00:42 -0800 |
| Last post | 2021-12-14 01:41 -0800 |
| Articles | 19 on this page of 59 — 20 participants |
Back to article view | Back to comp.lang.c++
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]
| From | wij <wyniijj@gmail.com> |
|---|---|
| Date | 2021-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]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-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]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-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]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2021-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]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-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]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2021-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]
| From | Paavo Helde <eesnimi@osa.pri.ee> |
|---|---|
| Date | 2021-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]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-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]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2021-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2021-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]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-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]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2021-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]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2021-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]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-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]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2021-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]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2021-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]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-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]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-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]
| From | wij <wyniijj@gmail.com> |
|---|---|
| Date | 2021-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