2012-10-31 74 views
3

我知道Valgrind以一種允許捕捉段錯誤的方式跟蹤內存。但是,爲什麼不捕獲以下段錯誤?Valgrind沒有捕捉到Segfaults

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). 
+0

該程序是否實際上分段錯誤? – Wug

+0

運行'valgrind'的參數是? – Grambot

+0

嗯,它確實說「應該」和「許多」,而不是「將」和「全部」:-P –

回答

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. 
+0

它不在這裏。奇怪的是,它只是索引80通過乾淨。對於79或81,它會檢測到錯誤。對於80,它沒有。 -80與-79和-81相同。 Valgrind版本3.8.1。 –

+0

這取決於堆的佈局,這取決於是否是32位或64位可執行文件以及C運行時間分配的其他塊。 – TomH

5

我想你賦予的權力用Valgrind的,而超出這是可能的。

它會嘗試檢測各種類型的錯誤並將它們報告給您,但它不可能檢測到所有錯誤,即使在它嘗試檢測到的某些類錯誤中也是如此。

在這種情況下,你正在處理的是一個越界寫入數組,如果valgrind設法捕獲它,將被報告爲「無效寫入」錯誤。通過跟蹤哪些地址是「有效的」來檢測這些地址,因爲它們是已知堆塊的一部分。

問題是,如果你索引得太過數組的開始或結尾,那麼實際上可能會得到一個地址,該地址是相鄰塊中的有效地址,因此valgrind看起來絕對是好的。爲了減少發生這種情況的機會,valgrind在塊的每一側添加了一個填充區域(稱爲「紅色區域」),但默認情況下只有16個字節。

如果使用--redzone-size=128選項增加紅色區域大小,則會發現valgrind在該程序中檢測到錯誤。

+0

確實,這解釋了它。我忘了Valgrind沒有看到C語義。它只能看到機器代碼,所以在Valgrind看到它的時候'x [80]'已經是一個地址了。它不知道你實際上在做'x + 80'。 –

+1

我在Valgrind中看不到'--redzone-size'標誌。此外,訪問N處的數組位置(因此它從0開始索引,因此位於數組之後的1個元素)也不會被Valgrind捕獲。 – darksky