I am trying to create a function in C language that reads a string of command line integers and takes the sum of all the numbers without causing arithmetic overflow/underflow. I understand most of overflow/underflow concepts, but am struggling to apply it to my function.
Here is the code that I have created thus far:
int main(int argc, char * argv[]) {
int sum = 0, i;
if (argc <= 1) {
printf(" Enter integers into command line after command to run .exe file ");
exit(0);
} else {
for (i = 1; i < argc; i ) {
sum = atoi(argv[i]);
}
}
printf(" Sum of all command line arguments is %d ", sum);
}
I am curious to see if this addresses arithmetic overflow/underflow or if it is still missing something.
CodePudding user response:
if this addresses arithmetic overflow/underflow or if it is still missing something.
OP's code has no certain overflow protection. atoi()
on overflow is undefined behavior (UB). On overflow, it might return a large int
, might "wrap", might do terrible things - it is UB.
Instead of atoi()
, use strtol()
to detect string to integer overflow. Look at errno
after calling strtol()
.
errno = 0;
long val = strtol(argv[i], 0, 10);
if (errno) {
Handle_Overflow();
}
Rather than just add, look for potential overflow before doing the addition as overflow of signed integer overflow is more UB.
long sum = 0;
...
if ((val < 0) ? (sum < LONG_MIN - val) : (sum > LONG_MAX - val)) {
Handle_Overflow();
} else {
sum = val;
}
Could use widest integer type intmax_t
for maximal usable range without resorting to multi-objects.
A sum less than the a signed integer's range is sometimes called underflow. More commonly that is simply called overflow too.
intmax_t sum = 0;
for (i = 1; i < argc; i ) {
char *endptr;
errno = 0;
intmax_t val = strtoimax(argv[i], &endptr, 10);
if (endptr == argv[i] || *endptr) {
Handle_non_numeric_input();
}
if (errno == ERANGE) {
Handle_overflow();
}
if ((val < 0) ? (sum < INTMAX_MIN - val) : (sum > INTMAX_MAX - val)) {
Handle_Overflow();
}
sum = val;
}
printf(" Sum of all command line arguments is %jd\n", sum);
CodePudding user response:
If you pass two arguments, both of which are INT_MAX/2 10
(1,073,741,834
on 32-bit platform), then the sum should properly be INT_MAX 20
, which clearly overflows an int
.
I see nothing that would "address" that overflow.
This is how I would address it:
for (i = 1; i < argc; i ) {
// if sum argv[i] > INT_MAX, then show an error message.
if (INT_MAX - sum > atoi(argv[i]))
{
printf("The next sum will overflow!\n");
exit();
}
sum = atoi(argv[i]);
}
A more complete and correct implementation would have to consider if sum
and argv[i]
are positive or negative values. But I think this illustrates the basic idea for starters.