使用%d格式符的fscanf是否会引发缓冲区溢出?Fortify误报分析
Fortify检测
fscanf("%d")缓冲区溢出的疑问解答 是否为误报?
这不算严格意义上的误报,但风险触发场景非常极端。Fortify之所以告警,是因为%d格式符没有显式限制输入长度,当输入的十进制整数超出int类型的可表示范围时,会触发C标准中的未定义行为——这种行为理论上可能导致写入int内存之外的区域,比如篡改数组相邻元素的内存。不过正常业务场景下的合法输入不会触发,但恶意构造的超大数值输入存在潜在风险。
传入int地址是否可能越界?
是的,但仅在输入数值超出int的取值范围时才会触发。举个例子:如果系统中int是4字节(取值范围为-2^31到2^31-1),当输入一个远大于2^31-1的十进制数时,fscanf无法将其完整存入int变量,此时的行为是未定义的,极端情况下可能溢出到_RWHour数组的相邻内存位置,甚至更远处。
安全规避方案
针对这个问题,有几种可靠的修复方式:
限制输入长度+范围校验
给%d加上长度限制,同时在读取后校验数值是否在int的合法范围内:// 针对32位int限制最多10位输入(覆盖最大取值的十进制位数) if (fscanf(fp, "%10d", &_RWHour[i][j]) <= 0) { // 处理读取失败 } // 校验数值是否在int范围内 if (_RWHour[i][j] < INT_MIN || _RWHour[i][j] > INT_MAX) { // 处理超范围数值 }注意:如果是64位
int,需要把长度限制调整为19位。改用更可控的输入函数组合
用fgets读取固定长度的字符串,再配合strtol解析,这种方式能完全掌控输入处理流程:char input_buf[16]; // 足够容纳int类型的十进制字符串 if (fgets(input_buf, sizeof(input_buf), fp) == NULL) { // 读取失败处理 } char *end_ptr; errno = 0; long parsed_val = strtol(input_buf, &end_ptr, 10); // 多重校验:确保是有效整数、无多余字符、未超出范围 if (end_ptr == input_buf || (*end_ptr != '\n' && *end_ptr != '\0') || errno == ERANGE || parsed_val < INT_MIN || parsed_val > INT_MAX) { // 无效输入处理 } _RWHour[i][j] = (int)parsed_val;启用运行时边界检查
编译时开启编译器的未定义行为检测选项,比如GCC的-fsanitize=undefined,可以在运行时及时发现整数溢出等问题,提前排查风险。
内容的提问来源于stack exchange,提问作者Shane Bishop
相关产品推荐
相关产品推荐

