C++ Logo

liaison

Advanced search

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

From: Olivier Giroux <ogiroux_at_[hidden]>
Date: Wed, 15 Feb 2023 21:42:35 -0800
Yes, that’s a fun example.

A few thoughts in no particular order:
Specifying forward-progress is not trivial. The literature around it is not simple, the C++ specification of it is not simple, and it’s also unfinished in several places (my 2c). It’s not a good thing that C never mentions progress.
One reason the C++ specification of progress is not simple is to make room for vectorization and accelerator usage to expand. I believe C should want that. The thing that made us go there is the addition of parallelism in ‘17.
Saying that a loop doesn’t end, does nothing to prevent a compiler from reordering independent code around it. For example, suppose the call to puts() moved up inside main, but was still after the loop, then is it OK to hoist it above the loop? Forbidding compilers from moving code around loops without side-effects should be flat-out unacceptable, I think, so is there a another hidden requirement here? Does the loop also have to be assumed to have side-effects?

Speaking of loops with side-effects…

> [HANS]:
> We've of course always been able to write an infinite loop as:
>
> const volatile bool always_true = true;
> while (always_true) {
> ...
> }


This loop is already fine in both C and C++.

 Olivier Giroux

> On 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.png>
>
> On Wed, Feb 15, 2023 at 11:31 PM Robert Seacord <rcseacord_at_[hidden] <mailto: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] <mailto: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 05:42:52