Valgrind未捕获到段错误异常

4
我知道Valgrind以某种方式跟踪内存,可以捕获段错误。但是,为什么它没有捕获以下的段错误?
int main() {
    char *x = calloc(16, 1);
    char *y = calloc(16, 1);

    x[80] = 'c';
    y[-80] = 'c';

    printf("%c %c\n", *x, *y);
    return 0;
}

难道它不能捕获堆中越界访问吗?根据Valgrind的文档:

But it should detect many errors that could crash your program (eg. cause a segmentation fault).

1
程序是否真的出现了段错误? - Wug
你正在使用哪些参数运行 valgrind - Grambot
好吧,它确实说“应该”和“许多”,而不是“将会”和“全部” :-P - Nikos C.
2个回答

6

我认为你对valgrind的能力赋予了过高的期望。

它会尝试检测各种错误并向你报告,但它不可能检测所有错误,即使是它试图检测的某些错误类别。

在这种情况下,您正在处理的是对数组的越界写入,如果valgrind设法捕捉到它,将报告为“无效写入”错误。通过跟踪哪些地址是“有效”的,即它们是已知堆块的一部分,可以检测到这些错误。

问题在于,如果您将索引超出数组的开始或结尾太远,实际上您可能会得到一个地址,该地址是相邻块中的有效地址,因此在valgrind看来绝对没有问题。为了减少发生这种情况的机会,valgrind添加了一个填充区域(称为“红色区域”)在块的两侧,但默认情况下仅为16个字节。

如果您使用--redzone-size=128选项增加红色区域大小,则会发现valgrind会检测到此程序中的错误。


确实,这就解释了。我忘记Valgrind看不到C语言的语义。它只能看到机器代码,所以当Valgrind看到它时,x [80]已经是一个地址了。它无法知道你实际上正在执行 x + 80 - Nikos C.
2
我在Valgrind中看不到--redzone-size标志。此外,访问数组位置N(因为它从0开始索引,所以是数组的1个元素之外)也不会被Valgrind捕获。 - darksky

1

对我来说没问题:

==24344== Memcheck, a memory error detector.
==24344== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==24344== Using LibVEX rev 1854, a library for dynamic binary translation.
==24344== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==24344== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation framework.
==24344== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==24344== For more details, rerun with: -v
==24344== 
==24344== Invalid write of size 1
==24344==    at 0x8048419: main (testValgrind.c:5)
==24344==  Address 0x418f078 is 0 bytes after a block of size 16 alloc'd
==24344==    at 0x4021E22: calloc (vg_replace_malloc.c:397)
==24344==    by 0x804840F: main (testValgrind.c:3)
==24344== 
==24344== Invalid write of size 1
==24344==    at 0x8048422: main (testValgrind.c:6)
==24344==  Address 0x418f018 is 16 bytes before a block of size 16 alloc'd
==24344==    at 0x4021E22: calloc (vg_replace_malloc.c:397)
==24344==    by 0x80483F8: main (testValgrind.c:2)

==24344== 
==24344== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 1)
==24344== malloc/free: in use at exit: 32 bytes in 2 blocks.
==24344== malloc/free: 2 allocs, 0 frees, 32 bytes allocated.
==24344== For counts of detected errors, rerun with: -v
==24344== searching for pointers to 2 not-freed blocks.
==24344== checked 58,940 bytes.
==24344== 
==24344== LEAK SUMMARY:
==24344==    definitely lost: 32 bytes in 2 blocks.
==24344==      possibly lost: 0 bytes in 0 blocks.
==24344==    still reachable: 0 bytes in 0 blocks.
==24344==         suppressed: 0 bytes in 0 blocks.
==24344== Rerun with --leak-check=full to see details of leaked memory.

1
它在这里不起作用。奇怪的是,只有索引80能够完全通过。对于79或81,它会检测到错误。但是对于80,它不会。-80与-79和-81同理。Valgrind版本3.8.1。 - Nikos C.
这将取决于堆的布局,而堆的布局又取决于诸如可执行文件是32位还是64位以及C运行时分配了哪些其他块之类的因素。 - TomH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接