2011-11-09 154 views
0
char* x = malloc(512); 
memset(x, 0, 513); 
free(x); 

这是为什么这个程序崩溃?这是说free(): invalid pointer: 0x0000000000614010 这没有任何意义,如果有的话它应该破坏程序的一些其他随机部分,因为它写入未定义的内存空间。为什么这个指针无效?

+2

[鼻恶魔](http://catb.org/jargon/html/N/nasal-demons.html)! – ephemient

回答

14

你已经导致了未定义的行为,所以什么都可能发生。在这种情况下,您的free()实现可能会在缓冲区之后立即检查空间中的某些信息。既然你把它覆盖了,那就是游戏结束了。

+4

+1游戏结束 – orlp

+0

@Carl哦上帝,这是讨厌的。我一直认为“未定义”的意思是:“可能会有一些崩溃”。看起来供应商只是在这些场合实施随机的东西!很有帮助的实现。 – Blub

+4

@Blub:Eehm,__no__。你宁愿错误'免费():无效指针:0x0000000000614010'或BSOD?究竟。你应该很高兴你甚至收到错误信息。 – orlp

0

您已经分配了512字节的内存,但正在向其写入513个字节。 free()大概是检查内存区域是否仍然有效(如果它包含您写过的保护字节,则不会)。

2

你是malloc ing 512字节,而你正在用memset写入513字节,所以你已经损坏了堆。

如果它不是很明显,它是未定义的行为。你因为溢出堆而写了一个用于管理堆结构的重要地址。

+0

-1,这个答案与_“你正在给x添加1”很有用_对包含_“x + = 1”_的问题很有用。 – orlp

+0

@nightcracker:这个答案很好;含义是“你在调用未定义的行为”。其他可能的解释只是猜测。 –

+0

@nightcracker我可以明确说明你正在导致未定义的行为,但我认为这很明显。无论如何,我直接阅读这个问题,原因是因为他通过写入太多字节来破坏堆。 – AusCBloke

3

我是新来的,但我希望我能回答这个问题,让您满意。

您正在通过覆盖分配的块的重要部分来激发未定义的行为。您正在删除该块上大小信息的第一个(高位字节),即由malloc编写。大多数C标准库使用Doug Lea Malloc追加和prepends一些字节到您的块,它们包含大小和使用信息。通过覆盖这个,你实际上销毁了free()调用成功所需的信息,并真正释放了malloc的内存。 malloc的某些实现不会这样做,并为块对齐和大小保留一个“带外”表(其他位置,而不覆盖它),并且一些只是预先附加/追加该信息。正如我所说,你的程序崩溃,因为你覆盖了重要的信息,没有它,free()就是不能做它应该做的事情。

0

堆分配器在分配内存之前和/或之后立即放置一些簿记信息是很常见的。你观察到的一个可能的解释是你已经覆盖了对内存分配器的操作至关重要的一些数据,可能是分配的块的大小或下一个可用空间的位置。

在任何情况下,在您分配的空间范围之外写入都是未定义的行为,并且可能发生任何事情。仅仅因为这是现在发生的事情并不意味着它会发生在不同的系统上,甚至在不同的时间在同一个系统上。相反,即使你没有看到错误,这并不意味着未定义的行为不会被调用。这是使用不安全语言的成本,例如C.