为什么C编译器不对malloc大小错误发出警告?



我做了一个成员结构,我在我的iOS应用程序的ViewDidLoad中分配。我使用malloc为这个结构分配空间,然后在整个类中使用。这样的:

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

但我真正做的是:

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

我不小心将malloc调用中的sizeof()设置为不同的结构体(大小不同)。我很长一段时间都没有注意到这个错误,因为应用很少崩溃。操作系统的更新导致更频繁地发生崩溃。

我的问题是,为什么编译器不能警告这种事情?这是编译器不知道的还是允许用户任意设置malloc的设计选择?

"我怎样才能更快地找到这个错误?"

有很多方法可以更快地找到错误。

解决方案# 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类型的指针,这与struct y类型的sizeof操作数不兼容

解决方案# 2

建议这样写代码:

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

以后就这样做吧。这不仅不容易出错,而且更容易记住。

解决方案# 3

使用Swift或c++这样的语言,语言的类型系统可以帮助你避免这种错误。C语言在很多方面都不那么宽容。它是在20世纪70年代早期发明的,如果你想使用它,你必须接受它,这些类型的错误是c++和Swift存在的主要原因之一。

解决方案# 4

使用运行时内存边界检查器,如地址消毒程序。这将在访问内存时检测错误,而不是在分配内存时检测错误,但它仍然会为访问和分配(如果内存已被释放,则为free)提供堆栈跟踪。现在任何写C的人都应该熟悉地址消毒器和它的朋友,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文档关于内存分配

相关内容

  • 没有找到相关文章

最新更新