C++ Logo

std-proposals

Advanced search

Re: [std-proposals] D3666R0 Bit-precise integers

From: Oliver Hunt <oliver_at_[hidden]>
Date: Fri, 05 Sep 2025 03:50:36 -0700
> On Sep 5, 2025, at 12:57 AM, David Brown <david.brown_at_[hidden]> wrote:
>
>
>
> On 04/09/2025 19:22, Oliver Hunt wrote:
>> Sigh. Early send.
>>>> The correct way to say “signed overflow is an error” is to say “signed overflow is erroneous behavior”. That makes it explicit that the overflow is an error, and it permits developers to rely on consistent and deterministic behavior, rather than dealing with an adversarial compiler that is blindly assuming that it cannot happen.
>>>
>>> What do you mean by "erroneous behaviour" ? What do you think the C++ standards mean by that term (define in C++26) ? Why do you think it is in any way better than "undefined behaviour" for signed integer overflow?
>> I mean exactly what the standard says.
>>>
>>> The point of the new concept of "erroneous behaviour" in C++26 is to strongly encourage (but not force) compilers to give warnings during compile time for some diagnosable errors (such as reading local variables before they are initialised or assigned), and to make it acceptable for conforming compilers to add run-time checks that halt with an error message some time after hitting "erroneous behaviour”.
>>> It does not actually make this a requirement - in effect, AFAIUI, "erroneous behaviour" means basically the same as "undefined behaviour" except that compilers are strongly encouraged to help developers see such issues at compile time and/or runtime in debug or sanitising modes.
>> I do not understand how you can possibly think that. Here is the literal definition of EB:
>> "well-defined behavior that the implementation is recommended to diagnose”
>> How do you get “the same as ub” from a definition that explicitly states that the behavior is well defined?
>
> It seems I have seriously misunderstood the C++26 term "erroneous behaviour" from something else I had read.
>
> I am still somewhat confused that behaviour can be "well-defined" and also "if the execution contains an operation specified as having erroneous behaviour, the implementation is permitted to issue a diagnostic and is permitted to terminate the execution at an unspecified time after the operation".
>
> Presumably if signed integer overflow were to be deemed "erroneous behaviour", it would then have to have defined behaviour (wrapping being the obvious choice), but toolchains would be allowed to have traps or halt with a diagnostic if an execution has an overflow (in the manner of gcc/clang sanitizers) ?


Correct, Erroneous Behavior is a behaviour that we consider likely to be wrong, but understand that saying “a compiler can pretend this does not happen” can lead to security vulnerabilities, and more importantly can lead to non-local code that impacts behavior in code that looks reasonable. The entire reason it exists is that saying something (overflow, uninitialized reads, etc) has some kind of defined behavior (actually defined, implementation defined, unspecified) also means the operation is definitionally correct.

Hence, from your statements it would be entirely reasonable to say overflow should be EB. Now this is an adhoc example, so may not be correct w.r.t UB spread but I believe it should be close:

if (correctly_implemented_addition_overflow_check(a, b)) {
   log(“tried to perform %d + %d but that overflows to produce %d\n”, a, b, a+b);
   abort();
}

If overflow is undefined I believe the entire branch can be removed, with EB it cannot. Mercifully optimizations around overflow and explicitly written code seems to specifically only result in removal of checks when the overflow check itself is UB, rather than back propagating UB overflow inside correct checks - not something that can be said about null dereferences, or - prior to C++26 - reading uninitialized variables. There are many cases of logging code that is found to have compiler visible UB, and that logging code was called on the error path of a safety check, and so the safety check was removed - the functional effect of which was the compiler turned an actually innocuous error into an exploitable one that was completely unrelated to the actual type or place of the UB.

—Oliver

Received on 2025-09-05 10:50:54