簡體   English   中英

為什么 C 編譯器不警告 malloc 大小錯誤?

[英]Why does the C compiler not warn about malloc size errors?

我創建了一個成員結構,該結構是在我的 iOS 應用程序的 ViewDidLoad 中分配的。 我使用 malloc 為這個結構分配空間,然后在我的課堂上使用。 像這樣:

self.myData = malloc(sizeof(MyData));

除了我真正做的是:

self.myData = malloc(sizeof(MyOtherStruct));

我不小心在 malloc 調用中將 sizeof() 設置為不同的結構(大小不同)。 我很長一段時間沒有注意到這個錯誤,因為該應用程序很少崩潰。 操作系統更新導致崩潰更頻繁地發生。

我的問題是,為什么編譯器不能對這種事情發出警告? 這是編譯器不知道的東西,還是允許用戶隨意分配任何大小的設計選擇?

“我怎樣才能更快地找到這個錯誤?”

有很多方法可以更快地找到錯誤。

解決方案#1

靜態分析器會捕獲此錯誤。 在 Xcode 中按 command-shift-B。 例如,采用以下代碼:

#include <stdlib.h>

struct x { double x; };
struct y { char y; };

int main(int argc, char **argv) {
    struct x *p = malloc(sizeof(struct y));
    p->x = 1.0;
    return 0;
}

運行分析器對我產生了這個錯誤:

'malloc' 的結果被轉換為類型為 'struct x' 的指針,該指針與 sizeof 操作數類型 'struct y' 不兼容

解決方案#2

建議以這種方式編寫代碼:

self.myData = malloc(sizeof(*self.myData));

以后就這樣做吧。 這不僅不容易出錯,而且更容易記住。

解決方案#3

使用 Swift 或 C++ 之類的語言,其中語言的類型系統可以幫助您避免此類錯誤。 C 在很多方面都不太寬容。 它是在70年代初發明的,你只是一種必須接受,如果你想使用它,而這些類型的錯誤是為什么C ++和斯威夫特在首位,甚至存在的理由的重要組成部分。

解決方案#4

使用運行時內存邊界檢查器,如地址清理器。 這將在訪問內存時檢測錯誤,而不是在分配內存時檢測錯誤,但它仍會為您提供訪問和分配(如果內存已釋放,則為空閑)的堆棧跟蹤。 現在任何寫 C 的人都應該熟悉 address sanitizer 及其朋友,tsan,ubsan 等。

Valgrind 也實現了相同的效果,但地址清理器對於常見用例具有更好的用戶體驗。

問的問題

編譯器只真正為您提供類型錯誤的錯誤和警告。 這不是類型錯誤,而是運行時錯誤。 編譯器可以檢測到一些“可能”的運行時錯誤,但數量很少。 諸如忘記使用malloc()的返回值之類的事情……例如,

void f(void) {
    malloc(1); // warning
}

編譯器也好不到哪里去。

同樣,這是 C++ 和 Swift 等新語言的推動力,它們的類型系統允許您在分配錯誤時產生錯誤,這也是靜態分析(這是一個棘手的問題)的推動力。

發生這種情況是因為 ARC 沒有責任處理malloc()甚至free()

ARC 只處理分配的對象,如[Object alloc]

在你的情況下,當你做self.myData = malloc(sizeof(MyOtherStruct)); ,例如可以解釋為:

self.myData = malloc(N*sizeof(MyData));
//what can represents self.myData[0]..self.myData[N-1]

最后,記住當你使用sizeof() ,它會告訴你類型的大小,你作為參數傳遞,在編譯時計算。

您可以查看此鏈接以獲取有關對象分配的更多信息

並查看有關內存分配的Apple 文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM