我正在努力开发四个基本内存分配例程malloc
、realloc
、calloc
和free
的调试实现(操作类似于 Electric Fence(,以调试嵌入式系统上的堆损坏,这些系统没有资源运行其他内存调试工具,或者不存在其他工具(例如, LynxOS 7.0 for PowerPC附带GCC 4.6.3,以及glibc和libstdc++的专有实现,其中不包括mtrace
系列函数(。
以下是 calloc 的源代码,来自 GCC libiberty 中的 calloc.c。
PTR
calloc (size_t nelem, size_t elsize)
{
register PTR ptr;
if (nelem == 0 || elsize == 0)
nelem = elsize = 1;
ptr = malloc (nelem * elsize);
if (ptr) bzero (ptr, nelem * elsize);
return ptr;
}
如果nelem
和elsize
都等于0
,为什么和都设置为等于1
?
如果我尝试分配大小为n
0
个块或大小n
0
块,这两种情况都会导致总字节数0
而不是1
字节的聚合分配吗?
是的,这只是糟糕的代码,这在libiberty/gnulib/等中并不意外。据我了解,如果malloc(0)
每次调用返回一个空指针而不是唯一指针,他们已经替换了malloc
,所以我看不出有任何充分的理由让calloc
传递 1 到malloc
而不是 0。此外,传递 1 中断/破坏调试工具,例如清理器,这些工具可以告诉您是否无意中取消了指向"零元素数组"的指针。
该代码也非常危险,因为它不检查乘法的溢出;要做到这一点,需要任何正确的calloc
实现。
TL;大卫:这个代码是垃圾。
如果 nelem 或 elsize == 零,为什么 calloc 会分配 1 个字节?
减少歧义。
calloc(0, x), calloc(x, 0), malloc(0)
成功后,可能会返回NULL
或非NULL
指针。 在这两种情况下,指针可能不会在不导致未定义行为(UB( 的情况下取消引用。
如果不成功,将返回NULL
指针。
通过确保分配大小大于 0,返回NULL
时没有歧义 -分配从此calloc()
失败。
请注意,更好的功能还可以检测产品溢出。
if (nelem == 0 || elsize == 0) {
nelem = elsize = 1;
} else if (SIZE_MAX/nelem > elsize) {
return NULL; // Too much for this implementation
}
...
关于Electric_Fence的进一步思考:
我希望该项目的malloc(0)
也能确保不分配 0 字节。 然而,简单地调用ptr = malloc (0); if (ptr) bzero (ptr, 0);
并不能将 1 个字节的分配归零。if (nelem == 0 || elsize == 0) nelem = elsize = 1;
确保分配至少为 1 个字节,并且该分配为零。