C++ Logo


Advanced search

Re: [wg14/wg21 liaison] [isocpp-parallel] Proposal: Trivial infinite loops are not Undefined Behavior

From: Hans Boehm <boehm_at_[hidden]>
Date: Thu, 16 Feb 2023 12:59:52 -0800
Indeed a weird and wonderful example that I hadn't seen before.

But this also involves some implementation QOI decisions that seem
questionable for other reasons. Should a compiler really remove the return
instruction if it can deduce that the function always encounters undefined
behavior? Clearly that's currently allowed. On the other hand, it always
adds type and memory-safety violations to programs that previously had
"less serious" UB. So as a QOI issue, I think I would argue against it.


On Wed, Feb 15, 2023 at 8:42 PM Robert Seacord <rcseacord_at_[hidden]> wrote:

> I'm not sure if someone has posted this example yet, but here is a fun
> example that compiles in both C and C++ with different results:
> #include <stdio.h>
> int main() {
> while (1)
> ;
> }
> void unreachable() {
> puts("Hello world!");
> }
> If you want to try it: https://godbolt.org/z/1d3hzseh4
> In C, this code produces an infinite loop while in C++ it does the
> following:
> [image: image.png]
> On Wed, Feb 15, 2023 at 11:31 PM Robert Seacord <rcseacord_at_[hidden]>
> wrote:
>> Hans,
>> I initiated this latest discussion on the WG14 reflector and I've
>> recently become a bit more active in WG21 (and my boss is JF who wrote this
>> paper).
>> Here is a recap of some of the history of this issue:
>> I can't find any forward progress guarantee in the C Standard. The word
>> "progress" does not appear anywhere in the standard.
>> Subclause 6.8.5, "Iteration statements" paragraph 5 says:
>> An iteration statement may be assumed by the implementation to terminate
>> if its controlling
>> expression is not a constant expression197), and none of the following
>> operations are performed in its
>> body, controlling expression or (in the case of a for statement) its
>> expression-3198):
>> — input/output operations
>> — accessing a volatile object
>> — synchronization or atomic operations.
>> 197) An omitted controlling expression is replaced by a nonzero constant,
>> which is a constant expression.
>> 198) This is intended to allow compiler transformations such as removal
>> of empty loops even when termination cannot be
>> proven.
>> N1509 proposes to eliminate 6.8.5p6 in the current WP as the author
>> believes it to be incompatible with C99. See also N1528, Item 6.30,
>> Response to N1509.
>> N1528 covers why the rules were added. N1509 was written to show a
>> compiler can determine the opposite as well.
>> In https://open-std.org/jtc1/sc22/wg14/www/docs/n1509.pdf [Walls]
>> contends that many C90/C99 programs rely on entrance to an unending loop to
>> proceed no further (within that thread). Those programs are relying on the
>> semantics of C99 6.8.5p4: "An iteration statement causes a statement called
>> the loop body to be executed repeatedly until the controlling expression
>> compares equal to 0."
>> N1528 breaks existing conforming programs. Adding an exception may solve
>> the intent of both papers. That approach should be run by Hans. We can
>> defer a decision and not affect getting a CD out, then respond to an NB
>> comment. We do want to be compatible with WG21.
>> ACTION Douglas to work with Larry to come up with the proposed words are:
>> Change 6.8.5p6 as follows:
>> An iteration statement whose controlling expression is not a constant
>> expression (or omitted), that performs no input/output operations, does not
>> access volatile objects, and performs no synchronization or atomic
>> operations in its body, controlling expression, or (in the case of a for
>> statement) its expression, may be assumed by the implementation to
>> terminate.
>> Decision: Adopt N1509, as modified above, to the C1X WP. result: 14, 0, 1
>> On Wed, Feb 15, 2023 at 8:29 PM Hans Boehm via Parallel <
>> parallel_at_[hidden]> wrote:
>>> I read the current C wording, and the one proposed here, as saying that
>>> while(true) {
>>> if (!cond) break;
>>> ...
>>> }
>>> may not be assumed to terminate, and is thus very different from
>>> while(cond) {
>>> ...
>>> }
>> This is a very confusing shorthand as "..." seems to imply any
>> syntactically correct statements and thus the first pattern is a subset of
>> the second pattern.
>>> I don't remember considering that before. This seems to be completely
>>> at odds with Olivier's goals. I also don't think this is a good idea, for
>>> purely loop optimization and understandability reasons. OTOH, some people
>>> on the WG14 list seem to think it is intentional and desired.
>> Unlike what I said to JF at the meeting, it no longer sounds easy to me
>>> to remove this C vs. C++ divergence. There seem to be some substantive
>>> issues here.
>> There is a strong desire in C to remain compatible with C++ and it's less
>> clear what the C requirement is. There is a requirement that "while (1);"
>> cannot be assumed to terminate as it is ubiquitous in environments where
>> you don't have the luxury of calling exit() or yielding to the scheduler.
>> I certainly wouldn't give up on compatibility at this point, and there is
>> still a small window to change the C23 language as we are going to a second
>> CD.
>> Thanks,
>> rCs

Received on 2023-02-16 21:00:06