今天继续看内核,发现有0字节的内存分配,觉得有点奇怪.自己写了一个测试程序.
void CTestDlg::OnOK()
{
char *p = (char*)malloc(0);
free(p);
}
发现居然是可以通过编译的,且分配的指针p有效.看了一下MSDN的malloc的描述:
If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item.
既然用户传0,malloc还分配一个有效内存地址,那这地址一定是内存控制块了.内存控制块应该是一段size很小的空间,起个运行时校验作用,由校验数据和校验码组成,这是个人推断了,MSDN上未有内存控制块的组成说明.下面我们会以代码验证这个推断.
char *p = (char*)malloc(0);
*p = 100;//改写了控制块的内存
return;//不释放
不释放自然不会有运行时库的堆检查了.但这种作法产生了0字节的内存泄露.
Detected memory leaks!
Dumping objects ->
{80} normal block at 0x00382FB8, 0 bytes long.
Data: <>
Object dump complete.
CSDN上有人曾有这种疑惑,但是未有人正确解答.见如下帖.
http://topic.csdn.net/u/20090310/20/0489b016-6425-4b15-a093-ea67cf75e15f.html
甚至有人说C++不允许new出0字节内存,我也试了一下,发现new0字节是可以的.
char *p = new char[0];
加上释放代码:
char *p = (char*)malloc(0);
*p = 100;//改写了控制块的内存
free(p);
return;
结果断言错误.
DAMAGE:after Normal block(#88) at 0x00382FB2
能看到的代码在crt/src/dbgheap.c 1178行 free调用_free_dbg函数。实现的代码看不到了。
原因是损坏了内存控制块。
改成如下方式:
char *p = (char*)malloc(0);
int a = *p; //保存块数据
//其它操作代码
*p = a;//释放前还原控制块
free(p);
return;
执行并退出程序,可以看到一切正常了。
最后回到内核代码8390.h alloc_eip_netdev(void)调用__alloc_eip_netdev(0);
struct net_device *__alloc_eip_netdev(int size)
{
struct net_device *dev = __alloc_ei_netdev(size);
if(dev)
dev->netdev_ops = &eip_netdev_ops;
return dev;
}
可以看到内核分配了0字节而且改写了。但为什么没出问题呢?
只有继续研究,等弄通后再在下一篇来解决这个疑惑了.