【问题标题】:Why does calloc allocate 1 byte if nelem or elsize == zero?如果 nelem 或 elsize == 零,为什么 calloc 分配 1 个字节?
【发布时间】:2020-02-14 22:41:52
【问题描述】:

我正在开发四个基本内存分配例程 mallocrealloccallocfree(类似于 Electric Fence 的操作)的调试实现,以调试嵌入式系统上的堆损坏。没有资源来运行其他内存调试工具,或者其他工具不存在(例如,用于 PowerPC 的 LynxOS 7.0 附带 GCC 4.6.3,以及不包括 mtrace 的 glibc 和 libstdc++ 的专有实现函数族)。

以下是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;
}

为什么nelemelsize 都设置为等于1,如果其中一个等于0

如果我尝试分配 0 大小为 nn 大小为 0 的块,这两种情况都不会导致总字节数为 0 的聚合分配,而不是 1字节?

【问题讨论】:

  • malloccalloc 按规范要求返回唯一值。
  • @KerrekSB 但是由于malloc() 已经有这个要求,calloc() 不需要自己检查。
  • @Barmar 我想到了你的想法,“因为 malloc() 已经有这个要求,所以 calloc() 不需要自己的检查。”。此处与冗余检查的功能区别在于,通过在此处执行此操作,1 字节分配为零。如果没有if (nelem == 0 || elsize == 0) nelem = elsize = 1;,分配将保持原样。
  • @chux 确实如此,但访问内存是未定义的行为,因此没有必要。
  • @Barmar 同意 UB,但这是一种称为 Electric Fence 的编码范例,可能需要确定性行为。

标签: c malloc calloc


【解决方案1】:

是的,这只是糟糕的代码,这在 libiberty/gnulib/etc 中并不意外。据我了解,如果 malloc(0) 返回一个空指针而不是每次调用的唯一指针,它们已经替换了 malloc,所以我看不出有什么好的理由让 calloc 将 1 传递给 malloc 而不是 0 . 此外,传递 1 会破坏/破坏调试工具(如消毒剂),它们可以告诉您是否无意中取消引用指向“零元素数组”的指针。

代码也非常危险,因为它不检查乘法是否溢出;需要对calloc 进行任何正确的实现。

TL;DR:这段代码是垃圾。

【讨论】:

    【解决方案2】:

    如果 nelem 或 elsize == 零,为什么 calloc 分配 1 个字节?

    为了减少歧义。

    calloc(0, x), calloc(x, 0), malloc(0),成功时可能返回NULL 或非NULL 指针。在这两种情况下,如果不引起 未定义的行为 (UB),指针可能不会被取消引用。

    不成功时,返回NULL 指针。

    通过确保分配大小大于 0,在返回 NULL 时没有歧义 - this 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 个字节并且分配为零。

    【讨论】:

      猜你喜欢
      • 2021-01-08
      • 2018-12-19
      • 1970-01-01
      • 2016-03-15
      • 2020-07-28
      • 2012-08-10
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多