一般情况下,C语言如何防止整数溢出?

Generally, How do I prevent integer overflow from happening in C language?

一般来说,如何防止整数溢出发生在C编程语言中?我的意思是,有什么功能可以防止吗? 最后, 整数溢出 会像 缓冲区溢出 那样让我被黑吗?

运行前检查结果是否会溢出

gcc 提供了一些辅助内置函数。

Built-in Function: bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
Built-in Function: bool __builtin_sadd_overflow (int a, int b, int *res)
Built-in Function: bool __builtin_saddl_overflow (long int a, long int b, long int *res)
Built-in Function: bool __builtin_saddll_overflow (long long int a, long long int b, long long int *res)
Built-in Function: bool __builtin_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
Built-in Function: bool __builtin_uaddl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
Built-in Function: bool __builtin_uaddll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)

    These built-in functions promote the first two operands into infinite precision signed type and perform addition on those promoted operands. The result is then cast to the type the third pointer argument points to and stored there. If the stored result is equal to the infinite precision result, the built-in functions return false, otherwise they return true. As the addition is performed in infinite signed precision, these built-in functions have fully defined behavior for all argument values.

    The first built-in function allows arbitrary integral types for operands and the result type must be pointer to some integral type other than enumerated or boolean type, the rest of the built-in functions have explicit integer types.

    The compiler will attempt to use hardware instructions to implement these built-in functions where possible, like conditional jump on overflow after addition, conditional jump on carry etc.

Built-in Function: bool __builtin_sub_overflow (type1 a, type2 b, type3 *res)
Built-in Function: bool __builtin_ssub_overflow (int a, int b, int *res)
Built-in Function: bool __builtin_ssubl_overflow (long int a, long int b, long int *res)
Built-in Function: bool __builtin_ssubll_overflow (long long int a, long long int b, long long int *res)
Built-in Function: bool __builtin_usub_overflow (unsigned int a, unsigned int b, unsigned int *res)
Built-in Function: bool __builtin_usubl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
Built-in Function: bool __builtin_usubll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)

    These built-in functions are similar to the add overflow checking built-in functions above, except they perform subtraction, subtract the second argument from the first one, instead of addition.

Built-in Function: bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
Built-in Function: bool __builtin_smul_overflow (int a, int b, int *res)
Built-in Function: bool __builtin_smull_overflow (long int a, long int b, long int *res)
Built-in Function: bool __builtin_smulll_overflow (long long int a, long long int b, long long int *res)
Built-in Function: bool __builtin_umul_overflow (unsigned int a, unsigned int b, unsigned int *res)
Built-in Function: bool __builtin_umull_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
Built-in Function: bool __builtin_umulll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)

    These built-in functions are similar to the add overflow checking built-in functions above, except they perform multiplication, instead of addition.

The following built-in functions allow checking if simple arithmetic operation would overflow.

Built-in Function: bool __builtin_add_overflow_p (type1 a, type2 b, type3 c)
Built-in Function: bool __builtin_sub_overflow_p (type1 a, type2 b, type3 c)
Built-in Function: bool __builtin_mul_overflow_p (type1 a, type2 b, type3 c)

整数溢出本身就是一个UB,可能会导致很多问题。但这取决于您的代码。如果不是指针运算或数组索引的部分,您将不会被“黑客攻击”

您无法完全阻止 integer-overflow。如果它发生了,它就会发生。首先,您需要仔细编码。

但是您可以尝试在赋值之前检查是否会发生溢出。

在分配给 intlong int 类型的 object 的情况下,检查 integer-overflow 的可移植方法是首先分配值到 long long int.

类型的 object

然后比较存储的值如果大于INT_MAX或者小于INT_MIN如果是int或者大于LONG_MAX或者小于LONG_MINlong int.

的情况下

如果是,您知道它超出了范围,您可以通过这种方式阻止 integer-overflow。

如果您想使用函数代替,可以将此技术封装到自己的自定义函数中,f.e.:

#include <limits.h>

// For int.

_Bool INT_OF_CHECK (long long int n)
{
    return ( n > INT_MAX || n < INT_MIN ) ? 1 : 0;  
}

// For long int.

_Bool LINT_OF_CHECK (long long int n)
{
    return ( n > LONG_MAX || n < LONG_MIN ) ? 1 : 0;  
}

函数 returns 1 如果值不在范围内,0 如果在范围内。

不幸的是,这种检查方法不适用于 long long int 本身的分配,但对于 int 以及 long int 它可能会有所帮助。

它还有一个缺点,就是它没有涵盖这种情况,当要分配的值甚至大于或小于 long long int 可以容纳的范围内时,而这里本身就会发生溢出, 但它只是一种可能的方法。

您可以在 header limits.h.

中找到的宏

每当你声明一个整型变量时:

  1. 实际考虑 large/small 它将包含一个数字。
  2. 实际考虑是需要签名还是不签名。无符号通常问题较少。
  3. stdint.h 中选择满足上述要求的 intn_tuintn_t 类型中的最小类型(如果您愿意,也可以选择 ...fast_t 等类型)。
  4. 如果需要,提出包含变量将保存的最大 and/or 最小值的整数常量,并在您进行算术运算时检查这些常量。

也就是说,不要漫无目的地在你的代码中乱写 int

除了溢出之外,有符号类型也可能因为其他原因而出现问题,即每当您需要进行按位算术时。为避免 over/underflow 和意外的带符号按位运算,您还需要了解各种


Is integer overflow going to get me hacked like buffer overflow or etc?

不一定,但是如果有人知道任何错误,当然可以利用它 - 正如您在几乎所有电脑游戏中看到的那样。

如果您想保证不会出现溢出,但可以考虑一点性能成本,请查看任意精度算术库(例如 tiny-bignum-c, or GNU Multiple Precision Arithmetic)。

自 C99 起:标准库数学函数通过设置 errno = ERANGE 报告溢出,因此您可以检查(记得在调用所述数学函数之前设置 errno = 0)。 math.h 定义了 HUGE_VAL 和相关的宏,您可以检查它们是否溢出,对于浮点错误,有 fenv 系列函数,请参阅有关 math_error(7) and fenv(3) 的手册。

假设您有两个 int 值 a、b,并且您想要检查 a+b 是否不会产生上溢或下溢。

有两种情况:a≥0和a≤0。第一种情况不能下溢。如果 b > INT_MAX - a 则溢出。在第二种情况下,您不能溢出。如果 b < INT_MIN - a,则可能出现下溢。作为单个表达式:

a >= 0 ? b > INT_MAX - a : b < INT_MIN - a