包装 malloc - C

9

我是一个C语言的初学者。在阅读git源代码时,我发现了这个malloc的包装函数。

void *xmalloc(size_t size)
{
    void *ret = malloc(size);
    if (!ret && !size)
        ret = malloc(1);
    if (!ret) {
        release_pack_memory(size, -1);
        ret = malloc(size);
        if (!ret && !size)
            ret = malloc(1);
        if (!ret)
            die("Out of memory, malloc failed");
    }
#ifdef XMALLOC_POISON
    memset(ret, 0xA5, size);
#endif
    return ret;
}

问题

  1. 我不明白他们为什么要使用 malloc(1)
  2. release_pack_memory 是干什么的,我在整个源代码中都找不到这个函数的实现。
  3. #ifdef XMALLOC_POISON memset(ret, 0xA5, size); 是干什么的?

我计划在我的项目中重用这个函数。这是一个好的 malloc 封装吗?

任何帮助都将不胜感激。


8
阅读现有复杂程序代码值得赞赏 - 我希望更多的开发者这样做。 - Lars
3
第二个问题的定义在sha1_file.c中(它与Git的打包对象有关的内存,可能),其原型在git-compat-util.h中。(提示:只要您查看Git源代码,请使用 git grep release_pack_memory 查找!) - Cascabel
1
@Lars:谢谢。 @Jefromi:git grep的观点很好。 - Navaneeth K N
1
我是C语言的初学者。在阅读Git源代码时,感觉自己像是跳进了深渊,但这种感觉真的很棒。 - Daniel Earwicker
4个回答

3
  1. 在某些平台上,malloc(0)无法正常工作,此时会分配一个字节的内存。允许分配长度为0的内存块简化了程序的高级逻辑。

  2. 未知。

  3. 通过将分配的内存填充为非零值,可以更容易地发现程序中使用未经正确初始化的内存而导致的错误:在这种情况下,程序几乎立即崩溃。由于填充内存需要时间,因此它被包裹在预处理器定义中,只有在需要时才编译。


1
'malloc(0)'的行为是由实现定义的。它要么返回一个空指针,要么返回一个指向零字节数据的非空指针(当然,您永远无法引用它)。C99 §7.20.3内存管理函数:“如果请求的空间大小为零,则行为是由实现定义的:要么返回空指针,要么行为就像大小为某些非零值一样,除了返回的指针不应用于访问对象。” - Jonathan Leffler

2
对于问题1:
标准并没有定义malloc(0)的行为。它可能返回有效指针,也可能返回NULL。不同的实现方式会有不同的处理方式,因此代码将会使用malloc(1)来获得一致的行为。
对于问题3:
它将缓冲区的内容设置为“奇怪”的东西。这样,你的代码就不会依赖于内容具体是什么(malloc无法保证)。

你推荐使用这个包装器吗? - Navaneeth K N
@Appu - 将0更改为1并进行memset是可以的。关于OOM策略的死亡取决于你正在编写什么。这种策略适用于执行一个操作并退出的命令行实用程序。对于长时间运行的服务器,该策略可能或可能不可行(您想要退出进程还是清理当前请求并重试)。对于通用库而言,这种策略是不可接受的,因为OOM的策略应由主应用程序决定。 - R Samuel Klatchko
好的观点。我将要编写的代码是为一个库而设计的。因此,我认为应该避免使用 die - Navaneeth K N
1
“它应该返回一个没有内存关联的有效指针,还是返回NULL?” - 哦,我可以回答,“是的”;-) 不确定您的答案是否清楚地表明实现必须执行其中之一。如果它是一个有效的指针,那么每次都是不同的。 - Steve Jessop

2

1

我对这个包装器不熟悉,但是它的作用如下:

1 - 如果指定了size=0,则分配1个字节,而不是底层malloc没有这样做

这可能是为了让调用者仍然可以对其进行释放(例如realloc)

2 我认为这是为了尝试强制底层内存子系统更努力地查找内存

3 XMALLOC_POISON强制缓冲区处于已知状态 这是常见做法,以防止和检测由未初始化数据引起的奇怪错误

其次 - 为什么要包装malloc。从想要做什么的想法开始,然后实现它或复制一个实现。包装malloc的原因

  1. 泄漏检测
  2. 使用分析
  3. 内存池
  4. 调试(如XMALLOC_POISON)
  5. 强制检查

几乎所有这些都可以使用valgrind完成 - 它可以做更多的事情。

“编写可靠代码”一书为1,4和5提供了良好的内存包装器集合。


谢谢你的回答。老实说,我在C语言世界里有点迷茫。为了避免犯错,我正在阅读其他程序代码,并找出他们如何编写代码。 - Navaneeth K N
2
这样做可能是为了让调用者仍然可以在其上进行免费的操作。我不知道git的源代码,但更有可能是为了确保调用者可以绝对将0返回视为错误,即使输入为0。或者可能是为了确保指向不同0大小分配的指针比较不同(“这不是您的零大小缓冲区,因此那一定不是您的行李箱!”)。 - Steve Jessop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接