C++ Logo

std-discussion

Advanced search

Re: Is this program undefined-behavior or implementation-defined behavior?

From: jim x <xmh970252187_at_[hidden]>
Date: Sat, 10 Oct 2026 09:56:39 +0800
I think you found an analogy example: the width of `int` is
implementation-defined; if the width is larger than `32`, there is no
integer overflow in your example; otherwise, the program is
undefined behavior because integer overflow occurs. From this perspective,
isn't the program implementation-defined because the behavior depends on
how the implementation specifies the width for the `int` type?

On Fri, Oct 9, 2026 at 11:23 PM Jennifier Burnett <jenni_at_[hidden]>
wrote:

> [intro.race] p17 says that. If volatile variables on a particular
> implementation are *not* defined to be atomic it applies.
>
> This is what I'm saying with the analogy to integer overflow, I'll give
> you an example. Consider the following program:
> ```
> int main()
> {
> int i = 2147483647 <(214)%20748-3647>;
> ++i;
> return 0;
> }
> ```
> Does this program have undefined behaviour? With a 32 bit int typical of
> modern systems, the answer would be yes, because I've deliberately caused
> the maximum 31 bit value to overflow, and integer overflow is undefined
> behaviour.
>
> However, I might decide to run this program on a 36 bit system, in which
> case it's completely fine, or I might compile it on GCC with `-fwrapv`, in
> which case integer overflow becomes defined behaviour.
>
> The original statement that the program has undefined behaviour doesn't
> become incorrect just because I can make up a situation in which it doesn't
> cause undefined behaviour. The point is that you cannot, in general, run
> that program on any C++ compiler and expect it to work. The program _only_
> works on specific implementations that meet certain criteria, on every
> other possible implementation the behaviour will be undefined.
>
> So, in your example your program *only* has defined behaviour when
> volatile variables are defined by the implementation to have atomic
> semantics. On any other possible implementation it will have undefined
> behaviour. Thus, it is, in general, undefined. The fact that we can invent
> a hypothetical implementation for which it would be well defined does not
> make that untrue.
>
> To put it as simply as possible:
> If the implementation says that volatile variables have atomic semantics
> your program does not have undefined behaviour. If the implementation does
> anything else then [intro.race] p17 applies and you have undefined
> behaviour. When people say this program has undefined behaviour they are
> simply alerting you to the fact that the second possibility exists.
>
>
> On 9 October 2026 10:51:29 BST, jim x <xmh970252187_at_[hidden]> wrote:
>
>> "integer overflow" is undefined behavior because the standard states
>> that. I ask which rule in the standard says that the program contains a
>> data race? Do you agree that the relevant rule is [intro.race] p17? If you
>> agree, then the crux is: why is at least one operation of `#1` and `#2` not
>> atomic?
>>
>> On Fri, Oct 9, 2026 at 5:46 PM Jennifier Burnett <jenni_at_[hidden]>
>> wrote:
>>
>>> Because the standard doesn't define it and an implementation isn't
>>> required to, nor is it required to ensure that any program that runs it has
>>> any sane behaviour.
>>>
>>> When we're saying undefined we don't mean "undefined on all
>>> implementations", that's impossible to claim because it's trivial to create
>>> an implementation that defines any given piece of behaviour - GCC has a
>>> command line option to make integer overflow defined, for example, but that
>>> doesn't mean integer overflow isn't undefined. When people say a program
>>> has undefined behaviour really what they mean is that it is that unless the
>>> implementation goes out of it's way to make it defined (like with your
>>> volatiles or GCC's integers), it'll be undefined.
>>>
>>>
>>> On 9 October 2026 10:22:28 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>>
>>>> The crux is: why do you think the program is undefined behavior without
>>>> knowing the semantics of the access that would be specified by the concrete
>>>> implementation? What's your reason for that?
>>>>
>>>> On Fri, Oct 9, 2026 at 5:03 PM Jennifier Burnett <jenni_at_[hidden]>
>>>> wrote:
>>>>
>>>>> The crux of what I'm saying is that just because something is said to
>>>>> be undefined in the standard doesn't make it undefined on a particular
>>>>> implementation. In this hypothetical implementation accesses to volatile
>>>>> variables are documented to be atomic, so [intro.race] p17 does not apply
>>>>> and thus the behaviour is well-defined. A behaviour being defined by an
>>>>> implementation is different from something being implementation-defined, if
>>>>> that helps.
>>>>>
>>>>>
>>>>> On 9 October 2026 08:55:52 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>>>>
>>>>>> So, what behavior of the program do you think? If you think the
>>>>>> program should be undefined behavior because the program contains a data
>>>>>> race, let's step-by-step to go through the rules in [intro.race] p17. It's
>>>>>> true that `#1` and `#2` are two potentially concurrent conflicting actions,
>>>>>> and neither happens before the other. The crux is whether they satisfy the
>>>>>> condition: at least one of which is not atomic. If one of them is
>>>>>> non-atomic, then the condition is satisfied; therefore, the program
>>>>>> contains a data race. If they are both atomic operations, the condition is
>>>>>> false; no data race is contained. As I commented above, since the standard
>>>>>> lets implementations define the semantics of the access, and a
>>>>>> hypothetical implementation can define `#1` as `
>>>>>> std::atomic_ref<int>(value).load()` and `#2` as `
>>>>>> std::atomic_ref<int>(value).store(1)`; i.e., they're atomic
>>>>>> operations, I don't think the crux condition in [intro.race] p17 is true.
>>>>>> So, the program under this specified semantics shouldn't be UB. How do you
>>>>>> explain this point?
>>>>>>
>>>>>> On Fri, Oct 9, 2026 at 3:39 PM David Brown <david.brown_at_[hidden]>
>>>>>> wrote:
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 09/10/2026 09:16, jim x via Std-Discussion wrote:
>>>>>>> > If the implementation defines that accesses to volatile
>>>>>>> variables
>>>>>>> > are atomic, then they are atomic.
>>>>>>> >
>>>>>>> >
>>>>>>> > In this case, does the program contain a data race as per
>>>>>>> [intro.race]
>>>>>>> > p17? If not, since the behavior depends on how the implementation
>>>>>>> define
>>>>>>> > the semantics, does that mean the behavior of the program should
>>>>>>> be
>>>>>>> > implementation-defined?
>>>>>>> >
>>>>>>>
>>>>>>> "Implementation-defined" in the standards does not just mean that
>>>>>>> the
>>>>>>> implementation has to treat the construct in some particular way.
>>>>>>> It
>>>>>>> means that the standard gives a range of options of how the
>>>>>>> implementation should handle the construct, and that the
>>>>>>> implementation
>>>>>>> must document how it handles them.
>>>>>>>
>>>>>>> If an implementation's manual says that volatile accesses are atomic
>>>>>>> (not unreasonable on single-core non-superscaler targets like most
>>>>>>> microcontrollers), then the programmer can rely on the volatile
>>>>>>> accesses
>>>>>>> being atomic. But that does not mean unsynchronised volatile
>>>>>>> accesses
>>>>>>> to the same address in different threads is implementation-defined
>>>>>>> behaviour, or should be called such in the C++ standards.
>>>>>>>
>>>>>>>
>>>>>>>

Received on 2026-10-10 01:56:57