【转载】gcc.gnu.org:内置函数执行溢出检查算法

本文介绍了GCC编译器中的内置函数,用于检查整数运算可能发生的溢出情况,包括加法、减法和乘法,以及相应的无符号版本。通过使用这些函数,开发者可以在编译时进行安全检查,避免运行时意外溢出导致的问题。

转载:https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html

下面的内置函数可以执行简单的算术运算,并检查运算是否溢出。

内置函数:bool __builtin_add_overflow( type1 a, type2 b, type3 * res)
内置函数:bool __builtin_sadd_overflow(int a,int b,int * res)
内置函数:bool __builtin_saddl_overflow(长整数a,长整数b,长整数* res)
内置函数:bool __builtin_saddll_overflow(long long int a,long long int b,long long int * res)
内置函数:bool __builtin_uadd_overflow(无符号整数a,无符号整数b,无符号整数* res)
内置函数:bool __builtin_uaddl_overflow(无符号长整数a,无符号长整数b,无符号长整数* res)
内置函数:bool __builtin_uaddll_overflow(unsigned long long int a,unsigned long long int b,unsigned long long int * res)

这些内置函数将前两个操作数提升为无限精度带符号类型,并对这些提升的操作数执行加法运算。然后将结果强制转换为第三个指针参数指向的类型并存储在那里。如果存储的结果等于无限精度的结果,则内置函数返回 false ,否则返回 true 。由于加法运算以无穷大的符号精度执行,因此这些内置函数对所有参数值具有完全定义的行为。

第一个内置函数允许操作数的任意积分类型,结果类型必须是指向枚举型或布尔型以外的某个积分类型的指针,其余的内置函数都有明确的整数类型。

编译器会尽量使用硬件指令来实现这些内置函数,比如加法后溢出时的条件跳转,携带时的条件跳转等。

内置函数:bool __builtin_sub_overflow( type1 a, type2 b, type3 * res)
内置函数:bool __builtin_ssub_overflow(int a,int b,int * res)
内置函数:bool __builtin_ssubl_overflow(长整数a,长整数b,长整数* res)
内置函数:bool __builtin_ssubll_overflow(long long int a,long long int b,long long int * res)
内置函数:bool __builtin_usub_overflow(无符号整数a,无符号整数b,无符号整数* res)
内置函数:bool __builtin_usubl_overflow(无符号长整数a,无符号长整数b,无符号长整数* res)
内置函数:bool __builtin_usubll_overflow(无符号长整型a,无符号长整型b,无符号长整型* res)

这些内置函数与上面的加法溢出检查内置函数类似,只是它们执行的是减法,从第一个参数中减去第二个参数,而不是加法。

内置函数:bool __builtin_mul_overflow( type1 a, type2 b, type3 * res)
内置函数:bool __builtin_smul_overflow(int a,int b,int * res)
内置函数:bool __builtin_smull_overflow(长整数a,长整数b,长整数* res)
内置函数:bool __builtin_smulll_overflow(long long int a,long long int b,long long int * res)
内置函数:bool __builtin_umul_overflow(无符号整数a,无符号整数b,无符号整数* res)
内置函数:bool __builtin_umull_overflow(无符号长整数a,无符号长整数b,无符号长整数* res)
内置函数:bool __builtin_umulll_overflow(unsigned long long int a,unsigned long long int b,unsigned long long int * res)

这些内置函数与上面的加法溢出检查内置函数类似,只是它们执行的是乘法,而不是加法。

下列内置函数可以检查简单的算术运算是否会溢出。

内置函数:bool __builtin_add_overflow_p( type1 a, type2 b, type3 c)
内置函数:bool __builtin_sub_overflow_p( type1 a, type2 b, type3 c)
内置函数:bool __builtin_mul_overflow_p( type1 a, type2 b, type3 c)

这些内置函数类似于 __builtin_add_overflow , __builtin_sub_overflow 或 __builtin_mul_overflow ,不同之处在于它们不将算术运算的结果存储在任何地方,并且最后一个参数不是指针,而是某些具有枚举或布尔类型以外的整数类型的表达式。

内置函数将前两个操作数提升为无限精度带符号类型,并对这些提升的操作数执行加法运算。然后将结果转换为第三个参数的类型。如果强制转换结果等于无限精度结果,则内置函数返回 false ,否则返回 true 。将忽略第三个参数的值,仅评估第三个参数中的副作用,并且不对最后一个参数执行积分参数提升。如果第三个参数是位字段,则用于结果强制转换的类型具有给定位字段的精度和正负号,而不是基础类型的精度和正负号。

例如,可以使用下面的宏在编译时可移植地检查两个常数整数相加是否会溢出,只有在已知安全的情况下才执行加法,并且不会触发一个-Woverflowwarning.

#define INT_ADD_OVERFLOW_P(a, b) \
   __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0)

enum {
    A = INT_MAX, B = 3,
    C = INT_ADD_OVERFLOW_P (A, B) ? 0 : A + B,
    D = __builtin_add_overflow_p (1, SCHAR_MAX, (signed char) 0)
};

编译器会尽量使用硬件指令来实现这些内置函数,比如加法后溢出时的条件跳转,携带时的条件跳转等。

Line 102: Char 14: ================================================================= ==22==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5030000000e4 at pc 0x55d840b2cda6 bp 0x7ffce95b8630 sp 0x7ffce95b8628 READ of size 4 at 0x5030000000e4 thread T0 #0 0x55d840b2cda5 in operator()<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, const int> /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/predefined_ops.h:69:24 #1 0x55d840b2cda5 in __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>> std::__lower_bound<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, int, __gnu_cxx::__ops::_Iter_less_val>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, int const&, __gnu_cxx::__ops::_Iter_less_val) /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:1501:8 #2 0x55d840b27716 in lower_bound<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, int> /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/stl_algobase.h:1536:14 #3 0x55d840b27716 in Solution::build(int) solution.cpp:102:14 #4 0x55d840b267ad in Solution::solve(std::vector<std::vector<int, std::allocator<int>>, std::allocator<std::vector<int, std::allocator<int>>>>&, int) solution.cpp:102:1 #5 0x55d840b2600e in Solution::minCostConnectPoints(std::vector<std::vector<int, std::allocator<int>>, std::allocator<std::vector<int, std::allocator<int>>>>&) solution.cpp:102:1 #6 0x55d840b25724 in __helper__ solution.cpp:102:28 #7 0x55d840b25724 in main solution.cpp:102:40 #8 0x7f56839f11c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6) #9 0x7f56839f128a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6) #10 0x55d840a4f234 in _start (solution+0xb5234) 0x5030000000e4 is located 0 bytes after 20-byte region [0x503000000... 2939 more chars
最新发布
08-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值