Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing C integer overflow [closed]

Tags:

c++

c

linux

I have some code in a function which will change/update values with the increment/decrement operator. For example:

static void update_value(char op)
{
    if (op == '+')
        value++;    // uint32_t global value
    else
        value--;
}

The function does not check whether we've gone over/under max/min values. So the caller can call it 20 times when value is say 16. resulting in 2^32 - 1 - 4.

I'd like to guard against that but I would like to use standard library constants. I remember there was a size_t (or similar) variable that would represent the largest number that a uint32_t can hold.

I can't remember the exact constants nor the header where they were defined. Any help?

like image 639
s5s Avatar asked Nov 30 '12 14:11

s5s


2 Answers

In C the header file you want is <stdint.h> and the constant is UINT32_MAX

static void update_value(char op)
{
    if (op == '+')
        if ( value < (UINT32_MAX - 1))
            value++;    // uint32_t global value
        else
            printf("too big!\n");
    else
       if (value > 0)
           value--;
       else
           printf("too small!\n");
}

For C++ you can use any number of solutions found here: What's the C++ equivalent of UINT32_MAX?

like image 90
Mike Avatar answered Sep 18 '22 06:09

Mike


I've found that the most general solution is to check if the incremented value is in fact greater than the previous value, or if the decremented value is smaller than the previous value. This works only if the value is unsigned, independently of the size of the variable, and is pretty much as portable as C code ever gets.

static void update_value(char op)
{
  if (op == '+') {
    if (value + 1 > value) value ++;
  } else {
    if (value - 1 < value) value --;
  }
}

Note that the code may happen to work with signed values, but per the C standard this would be undefined behavior, and the compilers are free to replace if (value + 1 > value) ... with if (1) .... You should not use this code with signed values unless you have a process in place to audit the generated object code after it has been linked.

With gcc and clang, you'd need to add -fwrapv option to let this code work for signed values; with other compilers your mileage may vary.

A sane way of doing this is to be type-specific and use constants from limits.h. For example:

#include "limits.h"

static void update_int(char op, int *value)
{
  int val = *value; // ignoring NULL pointer dereference

  if (op == '+') {
    if (val != INT_MAX) *value = val + 1;
  } else {
    if (val != INT_MIN) *value = val - 1;
  }
}

static void update_int(char op, unsigned int *value)
{
  unsigned int val = *value; // ignoring NULL pointer dereference

  if (op == '+') {
    if (val != UINT_MAX) *value = val + 1;
  } else {
    if (val != UINT_MIN) *value = val - 1;
  }
}
like image 28
Kuba hasn't forgotten Monica Avatar answered Sep 22 '22 06:09

Kuba hasn't forgotten Monica