防止C整数溢出

s5s*_*s5s 5 c c++ linux

我在函数中有一些代码,它将使用递增/递减运算符更改/更新值.例如:

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

该函数不会检查我们是否超过/低于最大/最小值.因此,当值为16时,调用者可以将其调用20次.结果为2 ^ 32 - 1 - 4.

我想提防,但我想使用标准库常量.我记得有一个size_t(或类似)变量代表uint32_t可以容纳的最大数字.

我不记得确切的常数和它们被定义的标题.有帮助吗?

Mik*_*ike 10

在C中,您想要的头文件是<stdint.h>常量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");
}
Run Code Online (Sandbox Code Playgroud)

对于C++,您可以使用此处的任意数量的解决方案:什么是UINT32_MAX的C++等价物?


Rei*_*ica 5

我发现最通用的解决方案是检查增加的值是否实际上大于先前的值,或者减少的值是否小于先前的值。这工作只有当值是无符号的独立变量的大小,并且是非常便携的C代码还未获得。

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

请注意,代码可能恰好适用于带符号的值,但是根据C标准,这将是未定义的行为,并且编译器可以自由替换if (value + 1 > value) ...if (0) ...。除非已链接生成的目标代码否则您应该使用该过程来审核生成的目标代码否则,请勿将此代码与带符号的值一起使用。

使用gcc和clang,您需要添加-fwrapv选项以使该代码适用于带符号的值;与其他编译器相比,您的工作量可能会有所不同。

做到这一点的唯一明智的方法是特定于类型并使用from中的常量limits.h。例如:

#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;
  }
}
Run Code Online (Sandbox Code Playgroud)