qidao123.com技术社区-IT企服评测·应用市场
标题:
《C和C++安全编码》课程条记——第五章 整数安全
[打印本页]
作者:
雁过留声
时间:
2025-5-15 00:10
标题:
《C和C++安全编码》课程条记——第五章 整数安全
一、整数安全导论
整数安全的核心抵牾在于:
数学理想
:整数在数学中是无限集合
计算机现实
:受限于硬件存储(通常4/8字节)和语言规范
典型问题场景:
隐式类型转换陷阱(如 signed/unsigned 混合运算)
边界条件失控(INT_MAX + 1)
存储截断错误(long → short)
平台差别问题(ILP32 vs LP64数据模型)
隐式转换陷阱:
int a = -1;
unsigned b = a; // 转为4294967295(32位系统)
复制代码
未定义行为:
int a = INT_MAX;
int b = a + 1;
复制代码
二、整数数据类型
类型体系对比
类型范围(32位)风险点int-2³¹ ~ 2³¹-1溢出为UBunsigned0 ~ 2³²-1回绕(0-1=UINT_MAX)char实现定义符号性需显式声明signed/unsigned 特性有符号类型无符号类型表树模围-2^(n-1) ~ 2^(n-1)-10 ~ 2^n-1溢出行为未定义行为(UB)明白定义的回绕典型用途通用计算、错误码位操作、数组索引零值扩展符号位扩展零扩展
关键特性
补码表示
:唯一零值,硬件运算高效(当代计算机尺度)
特别类型
:
size_t:足够大的无符号类型(sizeof返回值)
ptrdiff_t:指针差值的有符号类型
size_t len = sizeof(arr);
ptrdiff_t diff = p2 - p1;
复制代码
三、整数转换
转换规则(转换优先级)
整数提升
:
若原始类型范围≤int→提升为int,否则为unsigned int
unsigned char a = 0xFF;
int b = a; // 提升为int(255)
复制代码
普通算术转换
:
混合运算时按优先级转换(如signed+unsigned→unsigned)
int a = -5;
unsigned b = 10;
long c = a + b; // a转为UINT_MAX-4,结果可能非预期
复制代码
隐式转换风险矩阵
转换方向潜在风险示例有符号→无符号负值变极大正值int(-1) → unsigned(4294967295)宽类型→窄类型高位截断long(0x12345678) → short(0x5678)浮点→整数未定义行为(UB)int x = 1e30;
unsigned char a = 0xFF; // 255
unsigned char b = 0x01; // 1
// 情况1:直接比较(无提升)
if (a < b) { // 比较的是 255 < 1 → false
// 不会执行
}
// 情况2:提升为 int 后比较
if ((int)a < (int)b) { // 比较的是 255 < 1 → false(和情况1一样)
// 不会执行
}
// 情况3:危险的情况(涉及有符号和无符号混合运算)
signed char c = -1; // -1(有符号)
if (a < c) { // 提升为 int 后比较:255 < -1 → false(但可能不符合预期)
// 不会执行
}
复制代码
unsigned char a = 0xFF; // 255
signed char b = -1; // -1
// 开发者可能误以为比较的是 (unsigned char)-1 == 255
if (a < b) {
printf("a < b\n"); // 不会执行,因为实际比较的是 255 < -1(false)
} else {
printf("a >= b\n"); // 会执行
}
// 如果确实想比较回绕后的值,应该显式转换:
if (a < (unsigned char)b) { // 比较 255 < 255 → false
printf("a < (unsigned char)b\n");
}
复制代码
四、整数操作
安全范式
_Bool safe_add(int a, int b, int *res) {
if ((b > 0 && a > INT_MAX - b) ||
(b < 0 && a < INT_MIN - b)) {
return 0;
}
*res = a + b;
return 1;
}
复制代码
操作安全检测方法伤害案例加法if (a > INT_MAX - b) /*溢出*/INT_MAX + 1(UB)乘法if (a > INT_MAX / b) /*溢出*/INT_MIN * -1(UB)移位右操作数必须∈[0,类型宽度-1]1 << 32(UB)除法检查除零和INT_MIN/-1INT_MIN / -1(UB)
汇编级检测
有符号溢出
:检查OF标志位(jo指令)
无符号回绕
:检查CF标志位(jc指令)
五、整数毛病
毛病模式
缓冲区溢出
(45%):
int buf[10];
buf[index] = x; // index未验证范围
复制代码
内存分配错误
(15%):
size_t size = x * y;
malloc(size); // 乘法可能回绕
复制代码
逻辑错误
(30%):
for (unsigned i = 5; i >= 0; i--) // 死循环(回绕)
复制代码
真实案例
CVE-2021-3156(sudo堆溢出)
:
size_t len = strlen(name);
char *buf = malloc(len + 2); // len+2可能回绕
复制代码
六、缓解策略
防御技能栈
层级措施代码层面使用安全库(如<stdckdint.h>)编译层面-ftrapv(有符号溢出陷阱)运行时ASLR、边界检查器硬件MPU内存保护单位
安全编码清单
所有外部输入验证范围
克制隐式signed/unsigned混用
数组索引显式检查上下界
内存分配前验证计算无溢出
启用编译选项(-Wall -Wextra)
int a = -5;
unsigned b = 10;
long c = a + b; // a转为UINT_MAX-4,结果可能非预期
复制代码
回绕检测:
if (UINT_MAX - a < b) { }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/)
Powered by Discuz! X3.4