If you have a potentially overflowing signed integer operation, you need to check if it overflows before performing the operation. Otherwise, if it overflows, your program will have undefined behavior and it could do or print just about anything.
In C23, ckd_add
, ckd_sub
and ckd_mul
was added which checks for overflow before doing the addition, subtraction or multiplication:
#include <inttypes.h>
#include <stdckdint.h> // chd_add, ckd_sub, ckd_mul
#include <stdint.h>
#include <stdio.h>
void foo() {
// ...
int32_t result;
if (ckd_add(&result, registers[rs], registers[rt])) {
fputs("arithmetic overflow\n", stderr);
} else {
printf("All's well, the result is %" PRId32 "\n", result);
}
}
If you can't use C23, you could make your own function that checks before adding:
bool add_int32(int32_t *result, int32_t lhs, int32_t rhs) {
// check if overflow would happen _before_ letting it happen:
if ((rhs > 0 && INT32_MAX - rhs < lhs) ||
(rhs < 0 && INT32_MIN - rhs > lhs))
{
return true; // overflow would happen
} else {
*result = lhs + rhs;
return false;
}
}
Note that the above hand-made function only handles int32_t
s while the standard ckd_add
is a macro using the _Generic
operator to handle all integer types (other than plain char
, bool
and enumeration types) in any combination, as-if it was a function with the signature:
bool ckd_add(int_type1 *result, int_type2 x, int_type3 y);
result
, after that it's too late. Once you have UB, all bets are off.a
andb
are greater than0
==>a+b > INT_MAX
==>a > INT_MAX - b
==>if (a > INT_MAX - b) DONOTADD(); else OkToAdd();
stdchkdint.h
... which is good and all, but there's no reason this should be UB either. Because on every ISA I know, signed overflow is well-defined. C should be prepared for working on real-world computers instead of fictional computers...