我前几天问了一个关于缓冲区溢出检测的问题(sprintf buffer global data overflow - how to detect it, Windows),问题只能通过cppcheck用标准函数(不是安全_s版本)来解决。
我更深入地改变了
的代码#include <stdio.h>
char buffer[2];
void main()
{
sprintf(buffer,"12345");
}
到
#include <stdio.h>
void f( char *b )
{
sprintf(b,"12345");
}
char buffer[2];
void main()
{
f( buffer );
}
Visual Studio 2012 / RTC可以在运行时处理堆栈分配的缓冲区溢出,但全局数据不会被检测到。
我想使用cppcheck无法进行深入分析,cppcheck-1.64无法检测到此问题。另外,我试图使用与AddressSanitizer(Windows)的clang也没有很好的结果。
是否可以防止Windows下的此类问题(最好是免费工具),如果不是,某些linux工具可能有帮助?
答案 0 :(得分:0)
您应该考虑使用sprintf
,而不是使用snprintf
。它的原型是(包含在标题stdio.h
) -
int snprintf(char *str, size_t size, const char *format, ...);
该函数将最多size
个字节(包括终止空字节)写入str
指向的缓冲区。因此,您应该更改函数f
签名以获取缓冲区的长度。另请注意,main
的签名应为以下之一 -
int main(void);
int main(int argc, char *argv[]);
我建议进行以下更改 -
#include <stdio.h>
void f(char *b, size_t len) {
sprintf(b, len, "12345");
}
char buffer[2];
int main(void) {
f(buffer, sizeof buffer);
return 0;
}
答案 1 :(得分:0)
这些是我们应该避免在我们的程序中使用全局变量的一些原因。 我不认为有这样的工具可以报告 全局变量(数据段)损坏。有很好的工具可用 用于检测堆栈和堆段内存损坏/溢出。
因此,为了避免这种情况,我们应该使用最小化全局变量的使用 在我们的计划中。如果不可能,我们应该尝试使用防御性编程 在使用这些时自己接近。只是为了说明你的程序可以 以下列方式重写,以避免全局内存损坏 程序中的场景。
#include <cstdio>
char buffer[2];
void f( char *b, size_t sz)
{
// Now we have protected our global variable from overrun by
// using the size information passed by caller.So even though
// client "12345" has been passed, it would just copy 12.
strncpy(b,"12345",sz);
}
int main() {
size_t tmp = sizeof(buffer)/sizeof(buffer[0]);
f( buffer, tmp);
return 0;
}
答案 2 :(得分:0)
我知道答案有点晚,但是在类似情况下仍然可以提供帮助。
Cppcheck不断改进,现在可以检测到此问题。
在分析第二个代码示例时,最新版本的Cppcheck(当前为1.86版)输出此错误消息:
Column1
我不确定它是否已在1.85版中运行,但绝对不能在1.84或更早版本中使用。 我想如果您隐藏全局缓冲区甚至更好,Cppcheck最终将不再能够检测到该问题。价值流分析有些复杂,需要一些资源(内存,时间,CPU)。