C++ Logo

std-proposals

Advanced search

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

From: David Brown <david.brown_at_[hidden]>
Date: Thu, 4 Sep 2025 14:51:28 +0200
On 04/09/2025 10:39, Marcin Jaczewski wrote:
> czw., 4 wrz 2025 o 08:32 David Brown <david.brown_at_[hidden]> napisaƂ(a):
>>
>>
>>
>> On 03/09/2025 21:09, Oliver Hunt wrote:
>>>
>>>
>>>> On Sep 3, 2025, at 4:53 AM, David Brown <david.brown_at_[hidden]> wrote:
>>>>>>
>>>>>> Do we /need/ UB on signed arithmetic overflow? No. Do we /want/ UB
>>>>>> on signed arithmetic overflow? Yes, IMHO. I am of the opinion that
>>>>>> it makes no sense to add two negative numbers and end up with a
>>>>>> positive number. There are very, very few situations where wrapping
>>>>>> behaviour on signed integer arithmetic is helpful - making it
>>>>>> defined as wrapping is simply saying that the language will pick a
>>>>>> nonsensical result that can lead to bugs and confusion, limit
>>>>>> optimisations and debugging, and cannot possibly give you a
>>>>>> mathematically correct answer, all in the name of claiming to avoid
>>>>>> undefined behaviour.
>>>>> This as argument for unspecified or implementation defined behavior,
>>>>> not introducing a brand new type, with *all* of the known security
>>>>> issues of `int` (that we decided were not necessary for the
>>>>> performance of unsigned integers).
>>>>
>>>> "int" does not, in itself, have "security issues". Incorrect
>>>> programming can have security implications. Overflow - whether
>>>> wrapping or UB, or anything else - is usually a bug in the code.
>>>> Giving a fixed definition to the incorrect value does not magically
>>>> fix the error in the code.
>>>
>>> No, Any new feature that introduces UB for no reason is a security
>>> feature, for the same reason that creating new types that introduce
>>> lifetime issues when used in a trivially obvious way (think: returning a
>>> string_view).
>>>
>>
>> Those are two wildly different things.
>>
>> Undefined behaviour is not in itself a security risk. /Incorrect/
>> behaviour is a security risk. It does not matter whether a program bug
>> has undefined behaviour, or defined and documented behaviour that is
>> different from expected. If a program hits a bug in the code, it is now
>> no longer doing what the programmer intended and predicted - and /that/
>> is a security risk (for code that is relevant for security).
>>
>> It does not matter if "a + b" overflows and has undefined behaviour, or
>> if "a + b" overflows and has defined but unexpected behaviour, such as
>> suddenly jumping in value.
>>
>
> To be devil's advocate, UB is worse as it is "viral", you not only get
> the wrong value but
> compiler can do unexpected things, like remove `if` that program tries
> to use to detect overflow.

/All/ incorrect code is viral in this sense. Once you've got a bug,
things can go badly wrong very quickly. If your calculations don't give
the correct value - the value that the programmer expects - then
everything afterwards that assumes the code was correct, is in jeopardy.
  If you have a routine calculating the thrust rate for a rocket, and
the calculations overflow, does it really matter if the next step is to
assume that an overflow could never have happened, or if you run with a
big negative thrust rate? (And if you had the foresight to check for
negative thrust rates, you should have had the foresight to check for
bad values before doing the overflowing calculations.)

It is arguably the case that UB can lead to disaster a bit quicker, but
getting meaningless well-defined results is not different in principle,
and not significantly less bad in practice.

C11 tried to standardise two types of undefined behaviour - "bounded
undefined behaviour" (which does not perform an "out-of-bounds store")
and "critical undefined behaviour" (which might do so). This optional
"Analyzability" annex has been ignored as impossible to implement and
useless even if it were possible. All you need is one little integer
calculation that is wrong, use it as the index of an array, and you can
stomp randomly over anything in memory - full-blown critical UB from a
simple coding error with fully defined behaviour at the point of the error.


> This is why standart try to move to Erroneous Behavior in many cases.
>

And that is why I don't think there is much benefit in doing that. But
it is good to encourage toolchains to check things when they can, so it
has that benefit to it.

> One thing for overflows to be "illegal" is that the program is
> portable to other sizes of `int`.
> Same program that works with `int` that has size of 16bit and does not
> have UB, it will work
> on machines that have 64bit int.
>

Code that is correct for a 16-bit int machine, with today's UB on
overflow semantics, will be correct on a 64-bit int machine (or more
realistically, a 32-bit int machine).

The same would apply for erroneous behaviour on overflow - it would have
no benefit or disadvantage, because hitting erroneous behaviour is as
much a bug in your code as hitting UB.

Code that is correct for a 16-bit int implementation that relies on
wrapping behaviour, on the other hand, will be wrong on a 32-bit int
machine.

Received on 2025-09-04 12:51:33