确保超出内存写入会立即触发故障

时间:2013-08-06 19:28:22

标签: c memory-leaks malloc

我很难跟踪一个与内存分配相关的非常典型的C bug。我的一个缓冲区是一个字节太短。结果,写了一个字节太多,超出了它的上限。

在大多数情况下,它没有效果;但在某些特定情况下,它会导致将来的操作失败(通常是malloc,或者是另一个函数中隐藏的malloc)。

这种错误难以跟踪的原因是它们不会出现在错误发生的位置,导致初始诊断错误。而且它也不会在调试模式下发生,使得搜索更加困难。

这种错误在C语言中非常常见,并且是该语言长期存在的弱点。

那么有什么可以帮助呢?

那么,如果“一个字节太多”写入触发立即故障,它将真正有用,首先检测问题的位置,但也检测到存在问题! (在前面的例子中,错误通过了所有测试并达到了生产阶段;梦魇情况......)。

这样的设置是否存在(在C中)? 我猜测如果存在一些解决方案,它可能与平台有关。但是,当然,如果存在便携式产品,我甚至会更感兴趣。

[编辑]感谢非常好的答案。我看到没有银弹解决方案,而是一套减轻问题的工具。我需要一些时间来研究你答案中提供的所有非常好的链接。

3 个答案:

答案 0 :(得分:1)

您可以使用gcc的-Wstack-protector。对于调试,您可以使用mudflap

答案 1 :(得分:1)

触发正常的即时故障可能很困难。但是有alternatives来解决这个问题。我最喜欢的是在valgrind下运行程序:任何有趣的业务都会被标记为非法读取或非法写入。

这是一个简单的错误计划:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *p = malloc(10);
    p[10] = 42;

    return 0;
}

这是我在valgrind下运行时得到的结果:

==11551== Invalid write of size 1
==11551==    at 0x40052A: main (main.c:7) # <------ compile with debugging symbols
==11551==  Address 0x51b904a is 0 bytes after a block of size 10 alloc'd
==11551==    at 0x4C28BED: malloc (vg_replace_malloc.c:263)
==11551==    by 0x40051D: main (main.c:6)
==11551== 

任何不太干扰的东西可能都具有较小的粒度(即它可能会错过一些非法访问)。我链接的维基页面有各种平台的替代品。

答案 2 :(得分:1)

有些工具可以在缓冲区后面写一个“红区”区域。红色区域将包含一个特殊关键字,可以定期检查(如在空闲时间,使用时间等)以确定缓冲区的健全性。这只会告诉你是否有问题....不是谁做了。

另一种解决方案是在缓冲区后立即“页面保护”页面。例如,

vaddr = mmap(2 pages); // buffer of 1 page, red zone 1 page
mprotect(vaddr+1 page, READ_ONLY);

这将捕获对红色区域页面的任何写入访问,并帮助抓住罪魁祸首。当然,afaik,mprotect()需要一个mmap的地址,粒度是1页。