1

几天前我问了一个关于缓冲区溢出检测的问题(sprintf 缓冲区全局数据溢出 - 如何检测它,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 没有检测到这个问题。此外,我还尝试将 clang 与 AddressSanitizer ( Windows ) 一起使用,但效果不佳。

是否可以在 Windows 下防止此类问题(最好是免费工具),如果不能,也许一些 linux 工具可以提供帮助?

4

3 回答 3

1

我知道答案有点晚了,但在类似情况下它仍然可以提供帮助。
Cppcheck 不断改进,现在能够检测到这个问题。
最新版本的 Cppcheck(目前为 1.86 版)在分析第二个代码示例时会输出此错误消息:

$ ./cppcheck global_buffer_overflow.c
Checking global_buffer_overflow.c ...
[global_buffer_overflow.c:10] -> [global_buffer_overflow.c:4]: (error) Buffer is accessed out of bounds: buffer

我不确定它是否已经在 1.85 版本中工作,但它绝对不适用于 1.84 或更早的版本。我想如果你隐藏全局缓冲区更好 Cppcheck 最终不再能够检测到问题。价值流分析有些复杂,需要一些资源(内存、时间、CPU)。

于 2018-12-21T14:43:44.333 回答
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;
}
于 2014-03-31T11:01:34.257 回答
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;
}
于 2014-03-31T11:03:39.530 回答