g++格式溢出检测机制:gcc对tm_mon范围识别及加1警告疑问
GCC sprintf缓冲区溢出警告的差异原因解析
场景1:直接使用tm_mon无警告的原因
对于代码:
char mm[3]; sprintf(mm, "%02d", date_struct->tm_mon); // tm_mon取值0到11
GCC的-Wformat-overflow静态分析机制会识别标准库结构体成员的既定范围:
struct tm的tm_mon是<time.h>定义的标准成员,C标准明确规定其取值范围为0到11- GCC内置的静态分析数据库预存了这个范围信息,因此能确定
%02d格式化后只会输出两位数字(00到11),加上字符串结束符\0刚好占用3字节,完全匹配缓冲区mm的大小,不会触发溢出警告。
场景2:tm_mon+1触发警告的原因
对于代码:
char mm[3]; sprintf(mm, "%02d", date_struct->tm_mon+1);
GCC的静态分析无法对运算后的表达式做精确范围推导:
- 尽管逻辑上
tm_mon+1的范围是1到12,格式化后同样是两位数字,但静态分析工具采取保守策略:它不会将tm_mon的原始范围和加法操作结合做精准运算,而是默认tm_mon可能被其他代码篡改(脱离标准规定的0-11范围),导致tm_mon+1可能是任意int值(比如三位数的数值) - 这种情况下,
%02d会输出超过2位的字符,加上结束符会超出mm的3字节容量,因此GCC触发"directive writing between 2 and 11 bytes into a region of size 3"的溢出警告。
内容的提问来源于stack exchange,提问作者malaise
相关产品推荐
相关产品推荐

