一般来说,在C编程语言中,我该如何避免整数溢出?我的意思是,是否有任何函数可以预防它发生?最后,整数溢出会像缓冲区溢出那样使我被黑客攻击吗?
一般来说,在C编程语言中,我该如何避免整数溢出?我的意思是,是否有任何函数可以预防它发生?最后,整数溢出会像缓冲区溢出那样使我被黑客攻击吗?
a >= 0 ? b > INT_MAX - a : b < INT_MIN - a
在操作之前检查结果是否会溢出。
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)
整数溢出本身就是未定义行为,可能会导致许多问题。但这取决于您的代码。如果它不是指针算术或数组索引的一部分,那么您将不会被“黑客攻击”。
type1,type2,type3
版本与具有显式参数类型的版本之间是否存在性能差异? - Emile Cormier整数溢出会像缓冲区溢出一样让我被黑客攻击吗?
不完全是,但如果有人意识到它,任何错误都可以被利用 - 正如你在几乎每个电脑游戏中看到的那样。
如果您想确保不会发生溢出,但可以接受一定的性能成本,请考虑使用任意精度算术库(例如 tiny-bignum-c 或 GNU Multiple Precision Arithmetic)。
自 C99 以来:标准库的数学函数通过设置 errno = ERANGE
来报告溢出,因此您可以检查它(在调用该数学函数之前记得设置 errno = 0
)。math.h
定义了 HUGE_VAL
和相关的宏,您可以检查是否发生了溢出,对于浮点数错误,则有 fenv
函数族,有关 math_error(7) 和 fenv(3) 的手册请参阅相关说明。
你无法完全防止整数溢出。如果发生了,就会发生。你需要在编码时非常小心。
但是,在赋值之前,你可以尝试检查是否可能发生溢出。
对于赋值给类型为int
或long int
的对象的情况,一种可移植的检查整数溢出的方法是首先将该值分配给类型为long long int
的对象。
然后比较存储的值是否大于INT_MAX
或小于INT_MIN
(对于int
)或大于LONG_MAX
或小于LONG_MIN
(对于long int
)。
如果是,你就知道它超出了范围,这样就可以防止整数溢出。
如果你想使用函数而不是直接调用代码,你可以将这个技巧封装到自己的自定义函数中,例如:
#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;
}
1
,如果值不符合范围,返回0
,如果符合范围。long long int
本身的赋值并不起作用,但对于int
和long int
可能有所帮助。long long int
可以容纳的范围更大或更小,而溢出会在此处发生,但它仅仅是一种可能的方法。limits.h
中找到宏。INT_OF_CHECK
的情况下,如果将大于 LLONG_MAX 或小于 LLONG_MIN 的值分配给 int
,会发生什么?此外,在实际进行算术运算(例如 x * y
)时,整数溢出经常发生,而不是在赋值时。而无符号整数根本不会溢出。 - P.PINT_OF_CHECK
的情况下,如果将大于 LLONG_MAX
或小于 LLONG_MIN
的值分配给 int 型变量会怎样?” - 是的,但我已经在上一段中承认了这一点。 - RobertS supports Monica Celliox * y
)时,整数溢出经常发生,而不是在赋值时发生。但这只是一种证明溢出可能发生的方法。还可以使用算术表达式作为函数参数并进行检查。正如我已经说过的那样,它并不能涵盖所有情况,但比没有好,人们可以使用这些函数来检查是否可能发生溢出(要求值为最大 LLONG_MAX
和最小 LLONG_MIN
)。 - RobertS supports Monica Celliounsigned
方法。 - RobertS supports Monica Cellio