c - 释放它们后真的应该将指针设置为 `NULL` 吗?

标签 c pointers free

关于为什么在释放它们之后应该将指针设置为 NULL 似乎有两个论点。

Avoid crashing when double-freeing pointers.

简而言之:第二次意外调用 free(),当它设置为 NULL 时不会崩溃。

  • 这几乎总是掩盖逻辑错误,因为没有理由再次调用 free()。让应用程序崩溃并能够修复它会更安全。

  • 不能保证会崩溃,因为有时会在同一地址分配新内存。

  • 双重释放主要发生在有两个指针指向同一个地址时。

逻辑错误也可能导致数据损坏。

Avoid reusing freed pointers

简短:如果 malloc() 在同一位置分配内存,除非已释放指针设置为 NULL

  • 如果偏移量足够大 (someStruct->lastMember, theArray[ someBigNumber]).不会崩溃,而是数据损坏。

  • 将指针设置为NULL 不能解决不同指针具有相同指针值的问题。

问题

这是 a post against blindly setting a pointer to NULL after freeing .

  • 哪个更难调试?
  • 是否有可能同时捕获两者?
  • 此类错误导致数据损坏而不是崩溃的可能性有多大?

请随意扩展这个问题。

最佳答案

第二个更重要:重新使用释放的指针可能是一个微妙的错误。您的代码保持正常工作,然后无缘无故地崩溃,因为一些看似无关的代码写入内存中,而重新使用的指针恰好指向该内存。

我曾经不得不处理别人编写的一个确实错误的程序。我的直觉告诉我,许多错误与释放内存后继续使用指针的草率尝试有关;我修改了代码以在释放内存后将指针设置为 NULL,然后 bam,空指针异常开始出现。在我修复了所有空指针异常之后,代码突然变得稳定了。

在我自己的代码中,我只调用我自己的函数,它是 free() 的包装器。它接受一个指向指针的指针,并在释放内存后将指针置空。在它调用 free 之前,它会调用 Assert(p != NULL); 所以它仍然会捕获对同一指针的两次释放尝试。

我的代码也做了其他事情,例如(仅在 DEBUG 构建中)在分配内存后立即用一个明显的值填充内存,在调用 free() 之前做同样的事情以防有指针等的副本Details here.

编辑:根据请求,这里是示例代码。

void
FreeAnything(void **pp)
{
    void *p;

    AssertWithMessage(pp != NULL, "need pointer-to-pointer, got null value");
    if (!pp)
        return;

    p = *pp;
    AssertWithMessage(p != NULL, "attempt to free a null pointer");
    if (!p)
        return;

    free(p);
    *pp = NULL;
}


// FOO is a typedef for a struct type
void
FreeInstanceOfFoo(FOO **pp)
{
    FOO *p;

    AssertWithMessage(pp != NULL, "need pointer-to-pointer, got null value");
    if (!pp)
        return;

    p = *pp;
    AssertWithMessage(p != NULL, "attempt to free a null FOO pointer");
    if (!p)
        return;

    AssertWithMessage(p->signature == FOO_SIG, "bad signature... is this really a FOO instance?");

    // free resources held by FOO instance
    if (p->storage_buffer)
        FreeAnything(&p->storage_buffer);
    if (p->other_resource)
        FreeAnything(&p->other_resource);

    // free FOO instance itself
    free(p);
    *pp = NULL;
}

评论:

在第二个函数中可以看到,我需要检查两个资源指针是否不为空,然后调用FreeAnything()。这是因为 assert() 会提示空指针。我有这个断言是为了检测双重释放的尝试,但我认为它实际上并没有为我捕获很多错误;如果您想省去断言,那么您可以省去检查并始终调用 FreeAnything()。除了断言之外,当您尝试使用 FreeAnything() 释放空指针时不会发生任何不良情况,因为它会检查指针并在它已经为空时返回。

我的实际函数名称更简洁,但我尝试为这个示例选择 self 记录的名称。此外,在我的实际代码中,我有仅调试代码,在调用 free() 之前用值 0xDC 填充缓冲区,这样如果我有一个额外的指针指向它内存(一个不会被清零的内存)很明显它指向的数据是虚假数据。我有一个宏,DEBUG_ONLY(),它在非调试构建中编译为空;和一个在结构上执行 sizeof() 的宏 FILL()。这两个同样有效:sizeof(FOO)sizeof(*pfoo)。所以这是 FILL() 宏:

#define FILL(p, b) \
    (memset((p), b, sizeof(*(p)))

这是在调用之前使用 FILL()0xDC 值放入的示例:

if (p->storage_buffer)
{
    DEBUG_ONLY(FILL(pfoo->storage_buffer, 0xDC);)
    FreeAnything(&p->storage_buffer);
}

使用这个的例子:

PFOO pfoo = ConstructNewInstanceOfFoo(arg0, arg1, arg2);
DoSomethingWithFooInstance(pfoo);
FreeInstanceOfFoo(&pfoo);
assert(pfoo == NULL); // FreeInstanceOfFoo() nulled the pointer so this never fires

关于c - 释放它们后真的应该将指针设置为 `NULL` 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1879550/

相关文章:

你能知道 free() 在 C 中是否成功而不崩溃吗?

c - Yocto/Poky : install and use shared library . 等在单独的层上

无法将字符添加到分配给 ""的字符指针

有人可以回顾一下这个练习吗?我是对的,但想澄清一些事情

c - 此函数中缺少 free() 导致内存泄漏

c - OpenHashing 分段故障

不能声明两个字符指针

c - 有没有办法获取短路数据的最后一个字节并将其保存到字符中

c - 段错误: Stack allocation in a C program in Ubuntu when bufffer>4M

c++ - 何时删除 try-catch block 中的指针