g++ 如何检测格式溢出

问题描述 投票:0回答:1

使用 gcc 版本 13.2.0 (Ubuntu 13.2.0-23ubuntu4) 以下代码编译正常:

char mm[3]; sprintf (mm, "%02d", date_struct->tm_mon); // tm_mon is from 0 to 11

gcc 如何知道 tm_mon 适合 2 位数字?它知道范围限制 0..11 吗?

以下代码会引发警告:

char mm[3]; sprintf (mm, "%02d", date_struct->tm_mon+1);

将 2 到 11 字节的指令写入大小为 3 的区域

gcc 会“忘记”范围吗?

g++ buffer-overflow
1个回答
0
投票

gcc 会“忘记”范围吗?

是的。

令我惊讶的是

gcc
知道
tm_mon
的范围,但毫不奇怪,一旦
tm_mon
变成表达式,它就会失去该范围。

理论上,

gcc
可以在编译时继续跟踪此类表达式,但最终这相当于停止问题,因此在遇到第一个
+
(或
-
)时立即停止对我来说似乎是合理的。

令人惊讶的是,使用

1000 * date_struct->tm_mon
不会 导致警告(但应该)。所以整个警告似乎都是半生不熟。


这是一个最小的重现:

#include <stdio.h> #include <time.h> #ifndef XXX #define XXX 0 #endif void fn(struct tm *date_struct) { char mm[3]; sprintf (mm, "%02d", date_struct->tm_mon + XXX); }
gcc --version
gcc (GCC) 14.2.1 20240801 (Red Hat 14.2.1-1)
...

gcc -c -Wall tt.c
 # no output

gcc -c -Wall tt.c -DXXX=1
tt.c:9:29: warning: ‘%02d’ directive writing between 2 and 11 bytes into a region of size 3 [-Wformat-overflow=]
    9 |   char mm[3]; sprintf (mm, "%02d", date_struct->tm_mon + XXX);
      |                             ^~~~
tt.c:9:28: note: directive argument in the range [-2147483647, 2147483647]
    9 |   char mm[3]; sprintf (mm, "%02d", date_struct->tm_mon + XXX);
      |                            ^~~~~~
tt.c:9:15: note: ‘sprintf’ output between 3 and 12 bytes into a destination of size 3
    9 |   char mm[3]; sprintf (mm, "%02d", date_struct->tm_mon + XXX);
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
© www.soinside.com 2019 - 2024. All rights reserved.