[英]Does gcc compiler have any option to recognize memory corruption at compile time?
[英]Is there any gcc compiler warning which could have caught this memory bug?
我已經有一段時間沒有對 C 編程了,而且我的指針 fu 已經降級了。 我犯了一個非常基本的錯誤,今天早上我花了一個多小時才找到我做了什么。 該錯誤在此處最少復制: https://godbolt.org/z/3MdzarP67 (我知道該程序在內存管理方面是荒謬的,只是顯示發生了什么)。
對realloc()
的第一次調用當然會中斷,因為它給出的指針指向堆棧 memory, valgrind
使這一點非常明顯。
我對自己有一個規則,只要我追蹤一個錯誤,如果有一個警告可能已經捕獲它,我就會在我的項目中啟用它。 通常情況並非如此,因為許多錯誤來自編譯器無法檢查的邏輯錯誤。
然而在這里我有點驚訝。 我們malloc()
然后立即重新分配該指針,使分配的 memory 無法訪問。 很明顯,返回的指針不在該if
塊的 scope 之外,並且永遠不會free()
'd。 也許期望編譯器分析調用並意識到我們正在嘗試realloc()
堆棧 memory 太過分了,但令我驚訝的是,我找不到任何關於malloc()
返回指針泄漏的事情對我大喊大叫。 甚至clang
的 static 分析儀scan-build
也沒有接受它,我嘗試了各種相關選項。
我能找到的最好的是-fsanitize=address
至少在崩潰期間打印出一些線索信息,而不是:
mremap_chunk(): invalid pointer
在 Godbolt 上,或
realloc(): invalid old size
Aborted (core dumped)
在我的機器上,兩者都有些神秘(雖然是的,它們確實清楚地表明存在一些memory 問題)。 不過,這編譯沒有問題。
由於 Godbolt 鏈接不會永遠存在,這里是代碼的關鍵部分:
void add_foo_to_bar(struct Bar** b, Foo* f) {
if ((*b)->foos == NULL) {
(*b)->foos = (Foo*)malloc(sizeof(Foo));
// uncomment for correction
//(*b)->foos[(*b)->n_foos] = *f;
// obvious bug here, we leak memory by losing the returned pointer from malloc
// and assign the pointer to a stack address (&f1)
// comment below line for correction
(*b)->foos = f; // completely wrong
(*b)->n_foos++;
} else {
(*b)->foos = (Foo*)realloc((*b)->foos, ((*b)->n_foos + 1) * sizeof(Foo));
(*b)->foos[(*b)->n_foos] = *f;
(*b)->n_foos++;
}
}
發生錯誤是因為 f 是指向堆棧 memory 的指針(故意),但我們顯然不能分配應該是malloc()
的東西。
如果您的編譯器足夠新,請嘗試-fanalyzer
。 運行它時,我得到:
../main.c:30:28: warning: ‘realloc’ of ‘&f1’ which points to memory not on the heap [CWE-590] [-Wanalyzer-free-of-non-heap]
30 | (*b)->foos = (Foo*)realloc((*b)->foos, ((*b)->n_foos + 1) * sizeof(Foo));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
‘main’: events 1-2
|
| 37 | int main() {
| | ^~~~
| | |
| | (1) entry to ‘main’
|......
| 45 | add_foo_to_bar(&b, &f1);
| | ~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) calling ‘add_foo_to_bar’ from ‘main’
|
+--> ‘add_foo_to_bar’: events 3-5
|
| 19 | void add_foo_to_bar(struct Bar** b, Foo* f) {
| | ^~~~~~~~~~~~~~
| | |
| | (3) entry to ‘add_foo_to_bar’
| 20 | if ((*b)->foos == NULL) {
| | ~
| | |
| | (4) following ‘true’ branch...
| 21 | (*b)->foos = (Foo*)malloc(sizeof(Foo));
| | ~~~~
| | |
| | (5) ...to here
|
<------+
|
‘main’: events 6-7
|
| 45 | add_foo_to_bar(&b, &f1);
| | ^~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) returning to ‘main’ from ‘add_foo_to_bar’
| 46 | add_foo_to_bar(&b, &f2);
| | ~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (7) calling ‘add_foo_to_bar’ from ‘main’
|
+--> ‘add_foo_to_bar’: events 8-11
|
| 19 | void add_foo_to_bar(struct Bar** b, Foo* f) {
| | ^~~~~~~~~~~~~~
| | |
| | (8) entry to ‘add_foo_to_bar’
| 20 | if ((*b)->foos == NULL) {
| | ~
| | |
| | (9) following ‘false’ branch...
|......
| 30 | (*b)->foos = (Foo*)realloc((*b)->foos, ((*b)->n_foos + 1) * sizeof(Foo));
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (10) ...to here
| | (11) call to ‘realloc’ here
|
不,但是,運行時測試可以拯救你。
如果您可以節省執行開銷,我已經看到許多應用程序在 memory 分配中添加了一個額外的層,以跟蹤所做的分配並發現泄漏/錯誤。 通常他們用包含FILE和LINE的宏替換 malloc() 和 free()
可以在這里看到一個示例(檢查 Heap.c 和 Heap.h 文件) https://github.com/eclipse/paho.mqtt.c/tree/master/src
谷歌搜索“內存堆調試器”可能會出現其他示例。 或者你可以自己滾動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.