malloc() 之后写入指针越界不会导致错误
当我尝试下面的代码时它工作正常。我错过了什么吗?
main()
{
int *p;
p=malloc(sizeof(int));
printf("size of p=%d\n",sizeof(p));
p[500]=999999;
printf("p[0]=%d",p[500]);
return 0;
}
我用 malloc(0*sizeof(int)) 或其他东西尝试过,但它工作得很好。仅当我根本不使用 malloc 时,程序才会崩溃。因此,即使我为数组 p 分配 0 内存,它仍然可以正确存储值。那么为什么我还要为 malloc 烦恼呢?
when I try the code below it works fine. Am I missing something?
main()
{
int *p;
p=malloc(sizeof(int));
printf("size of p=%d\n",sizeof(p));
p[500]=999999;
printf("p[0]=%d",p[500]);
return 0;
}
I tried it with malloc(0*sizeof(int)) or anything but it works just fine. The program only crashes when I don't use malloc at all. So even if I allocate 0 memory for the array p, it still stores values properly. So why am I even bothering with malloc then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
它可能看起来工作正常,但根本不是很安全。通过在分配的内存块之外写入数据,您将覆盖一些不应该覆盖的数据。这是导致段错误和其他内存错误的最大原因之一,您在这个简短的程序中观察到的它似乎起作用,这使得追查根本原因变得如此困难。
阅读这篇文章,特别是有关内存损坏的部分,开始了解问题。
Valgrind 是一款出色的工具,用于分析内存错误(例如您提供的错误)。
@David 发表了很好的评论。将您的代码的运行结果与以下代码。请注意,后者会导致 ideone.com(单击链接)上出现运行时错误(几乎没有有用的输出!),而前者则如您所经历的那样成功。
It might appear to work fine, but it isn't very safe at all. By writing data outside the allocated block of memory you are overwriting some data you shouldn't. This is one of the greatest causes of segfaults and other memory errors, and what you're observing with it appearing to work in this short program is what makes it so difficult to hunt down the root cause.
Read this article, in particular the part on memory corruption, to begin understanding the problem.
Valgrind is an excellent tool for analysing memory errors such as the one you provide.
@David made a good comment. Compare the results of running your code to running the following code. Note the latter results in a runtime error (with pretty much no useful output!) on ideone.com (click on links), whereas the former succeeds as you experienced.
如果不分配内存,p 中有垃圾,因此写入它可能会失败。一旦进行了有效的 malloc 调用,p 就会指向有效的内存位置,您可以对其进行写入。你正在覆盖你不应该写的记忆,但没有人会握住你的手告诉你这件事。如果您运行程序和内存调试器(例如 valgrind),它会告诉您。
欢迎来到C。
If you don't allocate memory, p has garbage in it, so writing to it likely will fail. Once you made a valid malloc call, p is pointing to valid memory location and you can write to it. You are overwriting memory that you shouldn't write to, but nobody's going to hold your hand and tell you about it. If you run your program and a memory debugger such as valgrind, it will tell you.
Welcome to C.
超出记忆末尾的内容就是未定义行为™,这意味着任何事情都可能发生 - 包括您的程序运行,就好像您刚刚所做的事情是完全合法的一样。程序像执行了
malloc(501*sizeof(int))
一样运行的原因完全是特定于实现的,并且确实可以特定于任何事物,包括月相。Writing past the end of your memory is Undefined Behaviour™, which means that anything could happen- including your program operating as if what you just did was perfectly legal. The reason for your program running as if you had done
malloc(501*sizeof(int))
are completely implementation-specific, and can indeed be specific to anything, including the phase of the moon.这是因为无论您使用 malloc() 时使用什么大小,P 都会被分配一些地址。虽然,如果大小为零,您将引用无效内存,因为内存尚未分配,但它可能位于不会导致程序崩溃的位置内,尽管行为是未定义的。
现在,如果您不使用 malloc(),它将指向一个垃圾位置并尝试访问,这可能会导致程序崩溃。
This is because P would be assigned some address no matter what size you use with malloc(). Although, with a zero size you would be referencing invalid memory as the memory hasn't been allocated, but it may be within a location which wouldn't cause program crash, though the behavior will be undefined.
Now if you do not use malloc(), it would be pointing to a garbaging location and trying to access that is likely to cause program crash.
根据 C99,如果传递给 malloc 的大小为 0,C 运行时可以返回 NULL 指针,或者分配的行为就像请求是对于非零分配,但返回的指针不应被取消引用。所以它是实现定义的(例如,某些实现返回零长度缓冲区),在您的情况下,您不会返回 NULL 指针,但您正在使用不应该使用的指针。如果您在不同的运行时尝试它,您会发现可以得到一个 NULL 指针。
According to C99 if the size passed to
malloc
is 0, a C runtime can return either a NULL pointer or the allocation behaves as if the request was for non-zero allocation, except that the returned pointer should not be dereferenced. So it is implementation defined (e.g. some implementations return a zero-length buffer) and in your case you do not get a NULL pointer back, but you are using a pointer you should not be using.If you try it in a different runtime you could get a NULL pointer back.当您调用 malloc() 时,会为您从较大的页面中划分出一小块内存。
实际上并不在 32 位机器上分配 4 个字节(分配器将其填充到最小大小)+ 用于在其整个生命周期中跟踪块的堆元数据的大小(块根据其大小放置在 bin 中并标记为使用中)或由分配器释放)。 hxxp://en.wikipedia.org/wiki/Malloc 或更具体地说 hxxp://en.wikipedia.org/wiki/Malloc#dlmalloc_and_its_derivatives 如果您在 Linux 上进行测试。
因此,超出块范围的写入并不一定意味着您会崩溃。在 p+5000 处,您没有在为该初始块分配的页面边界之外进行写入,因此从技术上讲,您正在写入有效的映射地址。欢迎来到内存损坏。
http://www.google.com/search ?sourceid=chrome&ie=UTF-8&q=堆+溢出
When you call malloc() a small chunk of memory is carved out of a larger page for you.
Does not actually allocate 4 bytes on a 32bit machine (the allocator pads it up to a minimum size) + size of heap meta data used to track the chunk through its lifetime (chunks are placed in bins based on their size and marked in-use or free by the allocator). hxxp://en.wikipedia.org/wiki/Malloc or more specifically hxxp://en.wikipedia.org/wiki/Malloc#dlmalloc_and_its_derivatives if you're testing this on Linux.
So writing beyond the bounds of your chunk doesn't necessarily mean you are going to crash. At p+5000 you are not writing outside the bounds of the page allocated for that initial chunk so you are technically writing to a valid mapped address. Welcome to memory corruption.
http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=heap+overflows
我们的 CheckPointer 工具可以检测到此错误。它知道 p 的分配是 4 个字节的块,因此进行了分配,它位于 p 分配的区域之外。它会告诉你 p[500] 赋值是错误的。
Our CheckPointer tool can detect this error. It knows that the allocation of p was to a chunk of 4 bytes, and thus the assignment is made, it is outside the area for which p was allocated. It will tell you that the p[500] assignment is wrong.