使用malloc函数是否安全?

10

有人告诉我,使用malloc进行内存分配不再安全,虽然我不是C/C++专家,但是我已经用malloc和C/C++做了一些东西。有没有人知道我可能遇到的风险是什么?

引用他的话:

[...]但事实上,C/C++的弱点就是安全性,而致命的是malloc和滥用指针。C/C++是公认的不安全语言。[...]除了少数应用程序外,我不建议继续使用C++编程。"


C++通常使用newdelete而不是mallocfree - knittl
31
你所说的“安全”是什么意思?如果是你的“朋友”告诉你的,为什么不让他解释一下他的意思呢? - anon
3
模糊的概括毫无意义。如果你想声称某事是不安全的,就必须解释为什么会不安全。 - Martin York
2
挂锁是安全锁止门的一种方式吗?如果在足够高的栅栏和强大的门闩上正确使用,是的。malloc() 就像用来固定门闩到栅栏上的螺栓集合:要实现安全的软件需要正确使用挂锁,只要螺栓固定得牢靠,挂锁就会有用。类比地说,不正确使用 malloc() 就相当于挂锁上的松螺栓。例如,一个程序(围墙区域)可以实现 ACLs(挂锁),但如果使用 malloc() 存在漏洞(松螺栓),那么这个程序可能会被攻破(闯入门)。 - Heath Hunnicutt
11
你的“朋友”似乎非常无知,或者可能是个喜欢搅事的人。 - anon
显示剩余2条评论
12个回答

16
也许C++的newmalloc()更加安全,但这并不意味着malloc()比以前更加不安全。你的朋友有没有说为什么他认为它不安全?

然而,以下是您需要注意的几点:

1) 在使用C++时,当您在同一程序中同时使用malloc()/free()new/delete时,您需要小心。虽然这是可能且允许的,但是用malloc()分配的所有内容必须使用free()释放,而不能使用delete。同样,用new分配的所有内容都必须使用delete释放,而不能使用free()。(这个逻辑进一步扩展:如果您使用new[]分配数组,则必须使用delete[]释放,而不能只用delete。)请始终使用相应的对应对象进行分配和释放。

int* ni = new int;
free(ni);   // ERROR: don't do this!
delete ni;  // OK

int* mi = (int*)malloc(sizeof(int));
delete mi;  // ERROR!
free(mi);   // OK  

2) malloc()new(再谈C++)并不完全相同。 malloc() 只是给你一块可用的内存;如果可用,new 会额外调用构造函数。同样地,delete 会调用析构函数(如果有),但是 free() 则不会。这可能导致问题,例如对象未正确初始化(因为未调用构造函数)或未释放资源(因为未调用析构函数)。

3) C ++ 的 new 还负责为指定类型分配正确数量的内存,而你需要使用 malloc() 自行计算:

int *ni = new int;
int *mi = (int*)malloc(sizeof(int));  // required amount of memory must be
                                      // explicitly specified!
                                      // (in some situations, you can make this 
                                      // a little safer against code changes by
                                      // writing  sizeof(*mi)  instead.)

结论:

在 C++ 中,尽可能使用 new/delete,而不是 malloc()/free()。(在 C 中,new/delete 不可用,因此选择显然。)


1
不要忘记,C++实现可以自由地使用任何类型的分配函数来实现new,只要其行为符合标准即可。换句话说,malloc很可能会被调用以实现new的分配部分行为。 - Dustin
@Dustin: 这是正确的,但是这仍然不意味着您可以释放使用new分配的内容。您提到的是特定于实现的,因此没有任何保证;它不应影响您编写代码的方式。 - stakx - no longer contributing

14
实际上,那是错误的。 "C/C++"其实不存在。有"C"和"C++"两种语言,它们共享一些语法(或者说很多),但它们确实是非常不同的语言。
它们之间一个巨大的区别就是管理动态内存的方式。C的方法确实是使用malloc()/free(),如果你需要动态内存,那么很少有其他选择,只能使用它们(或者一些与malloc()类似的函数)。
而C++的方法则是根本不用手动处理动态资源(其中内存只是其中之一),资源管理被交给一些经过良好实现和测试的类,最好是标准库中的类,然后自动完成。例如,不需要手动处理以零结尾的字符缓冲区,可以使用std::string;不需要手动处理动态分配数组,可以使用std:vector;不需要手动处理打开文件,可以使用std::fstream系列的流等。

实际上,我只在处理原始格式的图像数组时使用向量类型。(OPENCV) - Felix
现在有C和C++两种编程语言。但这并不总是这样的情况(早期的C++实现将所有C++代码转换为C,然后使用C编译器进行编译)。他的朋友可能不熟悉过去的情况。 - J. Polfer
@sbi - 请阅读我所给出的答案,也许我的评论会更有意义...一些程序员对事物做出了错误的假设。 - J. Polfer
@sheepsimulator:我刚才看了,但我仍然不同意你的评论。 - sbi
3
+1 表示支持“C/C++ 不存在”。这是我非常讨厌的事情。 - Maulrus
显示剩余2条评论

9
您的朋友可能在谈论以下内容:
  • 使用指针的安全性。例如,在C++中,如果您正在使用malloc分配char数组,请考虑为什么不使用stringvector。指针本身并不是不安全的,但由于指针的错误使用而导致代码出现漏洞是不安全的。

  • 关于malloc的某些问题。大多数操作系统在将内存首次交给进程之前会清除内存,以保护安全。否则,一个应用程序中的敏感数据可能会泄露到另一个应用程序中。在不这样做的操作系统上,可以认为与malloc相关的不安全性实际上更与free有关。

您的朋友也可能不知道他在说什么。当有人说“X不安全”时,我的回答是:“在哪方面不安全?”。


1
我同意,看起来他的朋友是从C#/Java安全性的角度来说话的,认为所有指针都是邪恶的。 - deft_code

4
也许你的朋友年纪较大,对现在的事物不太熟悉 - 我曾经认为C和C++是一样的,直到我发现了过去10年中出现的许多关于该语言的新东西(我的大多数老师都是老派的贝尔实验室人员,主要使用C编写,并且只有粗略的C ++知识 - 贝尔实验室的工程师发明了C ++!)。 不要嘲笑他/她 - 你也可能会有这样的时候!
我认为你的朋友对于你必须自己进行内存管理感到不适 - 即易于犯错。 在这方面,它是不安全的,他/她是正确的...但是,可以通过良好的编程实践(例如RAII和使用智能指针)来克服这种不安全的方面。
然而,对于许多应用程序来说,具有自动垃圾回收可能已经足够了,一些程序员对指针的工作原理感到困惑,因此在没有一些培训的情况下使新手开发人员有效地编写C/C++可能会很困难。这也许是你的朋友认为应该避免使用C/C ++的原因。

3

这是C语言中本地分配和释放内存的唯一方式。如果使用不当,它可能会像其他任何东西一样不安全。微软提供了一些“安全”的其他函数版本,它们需要一个额外的size_t参数 - 也许您的朋友指的是类似的内容?如果是这种情况,他可能只是更喜欢calloc()而不是malloc()。


并不是所有的系统都需要手动分配内存。例如,Windows提供了LocalAllocHeapAllocGlobalAlloc等特定的API来进行内存分配。这些都是本地的。 - jweyrich
通过“本机”一词,我指的是“存在于标准C库中并在任何平台上都可用”的内容。LocalAlloc是微软特定的。 - mingos

2
如果您在使用C语言编程,除非有第三方库可以为您分配/管理内存,否则必须使用malloc来分配内存。当然,您的朋友说得没错,在C语言中编写安全代码尤其在分配内存和处理缓冲区时比较困难。但是我们都知道这一点,对吧? :)

也许他的意思是你应该使用calloc,这样返回的内存就被清零了。 - D.C.

2
他可能想要警告你的是指针的使用。如果你不了解它的工作原理,那么会引起问题。否则,请问一下你的朋友他的意思,或者让他提供证明他说法的参考资料。
malloc不安全就像说“不要使用X系统因为它不安全”。
在此之前,在C中使用malloc,在C++中使用new。如果你在C++中使用malloc,人们会看着你发疯,但在某些特定情况下这是可以接受的。

2

malloc本身并没有问题。你的朋友显然是指手动内存管理不安全且容易导致错误。与其他语言自动由垃圾收集器管理内存相比(并非不可能出现泄漏—现在没人关心程序在终止时是否清理,重要的是在程序运行时有东西占用内存),手动内存管理会更具风险。

当然,在C ++中您几乎根本不需要使用malloc(因为它根本不等同于new,并且通常假设您不只想获得原始内存)。此外,完全可以使用技巧编写程序,几乎可以彻底消除内存泄漏和破坏的可能性(RAII),但这需要专业知识。


哼,malloc不符合你的需求吗?天啊,原始内存才是王道,它证明了你作为程序员的实力。试着继承一个有数十万行C代码、成千上万个malloc和基于X窗口系统的C++程序。我们中的一些人并不介意malloc/free,并且不会混淆它们的工作方式和与new/delete的区别。但我想这取决于你在这个行业已经工作了多少年。我是一个老(但适应性强)老家伙。 - xcramps
@xcramps:在C++中,有一种正确的方式来使用原始内存,而不是使用malloc函数。你可以参考这个链接:http://www.icce.rug.nl/documents/cplusplus/cplusplus08.html#l128 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
Malloc对于原始内存来说很好,但如果你想要一个对象,那么它就不够用了。如果必须使用,可以使用malloc + placement new + 手动析构函数 + free。 - UncleBens

0
技术上讲, malloc 从一开始就不是安全的,但是除此之外,我唯一能想到的就是臭名昭著的“OOM killer”(OOM = out-of-memory),它是Linux内核使用的。 如果您愿意,可以阅读相关文档了解更多信息。 除此之外,我不认为 malloc 本身存在固有的不安全性。

“was never secure” 是什么意思?从哪个方面来说? - jweyrich
通过声明当前的malloc函数实现是不安全的,就意味着所有以相同方式运作的先前实现也是不安全的。换句话说,如果现在的malloc不安全,那么它从来就不安全。至于为什么它不安全,我真的不知道。我只是给予OP怀疑的余地。 :P - Dustin

0
在C++中,如果你遵循良好的规范,就不会有这样的问题。在C语言中,需要实践。Malloc本身并不是一个固有的不安全函数 - 人们只是不能充分处理它的结果。

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