ISO C permits removing overflow checks that rely on undefined behavior
The core issue
Signed integer overflow is undefined behavior in ISO C from C99 through C23. Because the standard does not require overflow to occur in any particular way, compilers are free to assume it never happens. This assumption enables an optimization: if an overflow check can only be true when overflow occurs, the compiler may delete the check as provably unreachable code.
Confirmed behavior across toolchains
GCC and Clang at -O1 and higher will remove signed overflow checks when the check's truth depends on undefined behavior. For example, code that tests a + b > a to detect addition overflow may be eliminated because the compiler assumes overflow never happens, making the comparison logically impossible.
MSVC exhibits similar behavior under /O2 and higher. The compiler treats signed overflow as unreachable, allowing it to prune defensive checks that cannot be true under the undefined-behavior assumption.
Portable detection idiom
To detect overflow before it occurs without relying on wraparound semantics, check the operands before performing the operation:
int safe_add(int a, int b, int *out) {
if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) {
return 0; // overflow detected
}
*out = a + b;
return 1; // success
}
This approach avoids the undefined behavior entirely by verifying the result will be representable before computing it. The same pattern applies to subtraction and multiplication, though multiplication requires additional bounds analysis.
Verification steps
- Compile your code with
-O2 and examine the assembly output to confirm whether the check survives.
- Use
-fsanitize=undefined (GCC/Clang) or /RTC1 (MSVC) to force runtime overflow detection during testing.
- Consider
-ftrapv (GCC) for trapping on overflow, though this affects performance and is not portable across all compilers.
Key constraints
- At
-O0, no optimizations occur, so checks remain intact.
- Compiler-specific flags can force overflow detection but alter performance characteristics.
- C23 maintains undefined behavior for most signed arithmetic overflow, so the problem persists.
One missing detail: If you need to verify whether a specific compiler version removes a particular check, please provide the compiler version and exact optimization flags used. This affects whether the check survives in your build environment.