cppfront
cppfront copied to clipboard
[SUGGESTION] Prevent signed overflow/underflow & unsigned carry
Suggestion As presented at CppCon 23, cppfront could transform integer arithmetic operations so that they trap/terminate on overflow, underflow or carry. This is a similar solution to my #220 suggestion.
A Cpp2 expression like this:
a + b
would lower to Cpp1 like this:
cpp2::checked_add(a, b)
For the situation where the programmer wants the Cpp1 behaviour (e.g. hashing, or performance where the programmer takes on the risk of overflow etc), Cpp2 could introduce new operators (like Swift has):
a &+ b
which would lower to Cpp1:
a + b
The cpp2::checked_add
function (and others for subtract, mul) could be implemented using compiler builtins or intrinsics, such as:
-
__builtin_add_overflow
-
_addcarry_u32
- C23's
ckd_add
or failing that, a manual implementation fallback option.
These builtins/intrinsics generally work like this:
int a = -1073741826;
int b = -1073741826;
int result = 0;
if (__builtin_add_overflow(a, b, &result)) {
std::terminate();
}
// `result` is OK
Will your feature suggestion eliminate X% of security vulnerabilities of a given kind in current C++ code?
Yes, there are many examples. See: https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=integer+overflow
Will your feature suggestion automate or eliminate X% of current C++ guidance literature?
Yes, see core guidelines:
- ES.103: Don’t overflow
- ES.104: Don’t underflow
Describe alternatives you've considered.
Instead of introducing the Swift-like operators to opt-out of the safe arithmetic (e.g. &+
), Cpp2 could have explicit functions like Rust:
-
wrapping_add
-
checked_add
However, the new operators allow for terser code closer to the original.
Thanks! It looks like GCC's intrinsics are supported on Clang, as usual, for all the versions of GCC and Clang that cppfront supports. Also Intel appears to support them all.
It's only just been added to MSVC though and using a different set of names.
The CERT C coding standard has implementations that could be used as the fallback option for compilers which don't have intrinsics:
Re MSVC, if targeting Windows 7+ or Server 2008 R2+ then the Intsafe.h header can be used, which provides functions like IntAdd
, LongLongAdd
, etc.
Also, for unsigned wrap, MSVC supports Intel intrinsics like _addcarry_u32
.
Is this worth doing in Cpp2? As soon as you wrap integer types in Cpp1 types, you no longer benefit.
a &+ b
isn't needed.
You just need a
or b
to not be a fundamental type.
For example, Cpp2 could provide cpp1_unsigned
as an alias for some unsigned
wrapper.
That wouldn't be picked up by the special cpp2::checked_add(a, b)
overload.
From https://github.com/hsutter/cppfront/discussions/649#discussioncomment-6869577:
Disclaimer: I dislike even mentioning a gross idea like wrapping fundamental types, it just screams "overhead!" But for the sake of discussion...