在释放它们之后,真的应该将指针设置为“NULL"吗?

本文介绍了在释放它们之后,真的应该将指针设置为“NULL"吗?的处理方法,对大家解决问题具有一定的参考价值

问题描述

似乎有两个论点为什么在释放它们之后应该设置一个指向 NULL 的指针.

There seem to be two arguments why one should set a pointer to NULL after freeing them.

简短:第二次调用 free(),当它设置为 NULL 时,意外地不会崩溃.

Short: Calling free() a second time, by accident, doesn't crash when it's set to NULL.

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

  • Almost always this masks a logical bug because there is no reason to call free() a second time. It's safer to let the application crash and be able to fix it.

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

It's not guaranteed to crash because sometimes new memory is allocated at the same address.

双空闲主要发生在有两个指针指向同一个地址时.

Double free occurs mostly when there are two pointers pointing to the same address.

逻辑错误也会导致数据损坏.

Logical errors can lead to data corruption too.

简短:如果 malloc() 在同一位置分配内存,访问释放的指针会导致数据损坏,除非释放的指针设置为 NULL

Short: Accessing freed pointers can cause data corruption if malloc() allocates memory in the same spot unless the freed pointer is set to NULL

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

  • There's no guarantee that the program crashes when accessing the NULL pointer, if the offset is big enough (someStruct->lastMember, theArray[someBigNumber]). Instead of crashing there will be data corruption.

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

Setting the pointer to NULL cannot solve the problem of having a different pointer with the same pointer value.

这是一篇帖子反对在释放后盲目地设置一个指向NULL的指针.

Here's a post against blindly setting a pointer to NULL after freeing.

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

随意扩展这个问题.

推荐答案

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

The second one is way more important: re-using a freed pointer can be a subtle error. Your code keeps right on working, and then crashes for no clear reason because some seemingly unrelated code wrote in the memory that the re-used pointer happens to be pointing at.

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

I once had to work on a really buggy program someone else wrote. My instincts told me that many of the bugs were related to sloppy attempts to keep using pointers after freeing the memory; I modified the code to set the pointers to NULL after freeing the memory, and bam, the null pointer exceptions started coming. After I fixed all the null pointer exceptions, suddenly the code was much more stable.

在我自己的代码中,我只调用我自己的函数,它是 free() 的包装器.它需要一个指向指针的指针,并在释放内存后将该指针归零.并且在它调用 free 之前,它调用 Assert(p != NULL); 所以它仍然会捕获对同一指针进行双重释放的尝试.

In my own code, I only call my own function that is a wrapper around free(). It takes a pointer-to-a-pointer, and nulls the pointer after freeing the memory. And before it calls free, it calls Assert(p != NULL); so it still catches attempts to double-free the same pointer.

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

My code does other things too, such as (in the DEBUG build only) filling memory with an obvious value immediately after allocating it, doing the same right before calling free() in case there is a copy of the pointer, etc. Details here.

根据请求,这里是示例代码.

per a request, here is example code.

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() 释放空指针时,没有什么不好的事情发生,因为它会检查指针,如果它已经为空则返回.

You can see in the second function that I need to check the two resource pointers to see if they are not null, and then call FreeAnything(). This is because of the assert() that will complain about a null pointer. I have that assert in order to detect an attempt to double-free, but I don't think it has actually caught many bugs for me; if you want to leave out the asserts, then you can leave out the check and just always call FreeAnything(). Other than the assert, nothing bad happens when you try to free a null pointer with FreeAnything() because it checks the pointer and just returns if it was already null.

我的实际函数名称更简洁,但我试图为这个例子选择自文档化的名称.另外,在我的实际代码中,我有只调试代码,在调用 free() 之前用值 0xDC 填充缓冲区,这样如果我有一个额外的指针内存(不会被清空的内存)很明显它指向的数据是虚假数据.我有一个宏,DEBUG_ONLY(),它在非调试版本中编译为空;和一个宏 FILL() 对结构执行 sizeof() .这两个同样有效:sizeof(FOO)sizeof(*pfoo).所以这里是 FILL() 宏:

My actual function names are rather more terse, but I tried to pick self-documenting names for this example. Also, in my actual code, I have debug-only code that fills buffers with the value 0xDC before calling free() so that if I have an extra pointer to that same memory (one that doesn't get nulled out) it becomes really obvious that the data it's pointing to is bogus data. I have a macro, DEBUG_ONLY(), which compiles to nothing on a non-debug build; and a macro FILL() that does a sizeof() on a struct. These two work equally well: sizeof(FOO) or sizeof(*pfoo). So here is the FILL() macro:

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

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

Here's an example of using FILL() to put the 0xDC values in before calling:

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

这篇关于在释放它们之后,真的应该将指针设置为“NULL"吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2

admin_action_{$_REQUEST[‘action’]}

do_action( "admin_action_{$_REQUEST[‘action’]}" )动作钩子::在发送“Action”请求变量时激发。Action Hook: Fires when an ‘action’ request variable is sent.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$_REQUEST['action']引用从GET或POST请求派生的操作。源码(Source)更新版本源码位置使用被使用2.6.0 wp-admin/admin.php:...

日期:2020-09-02 17:44:16 浏览:1170

admin_footer-{$GLOBALS[‘hook_suffix’]}

do_action( "admin_footer-{$GLOBALS[‘hook_suffix’]}", string $hook_suffix )操作挂钩:在默认页脚脚本之后打印脚本或数据。Action Hook: Print scripts or data after the default footer scripts.目录锚点:#说明#参数#源码说明(Description)钩子名的动态部分,$GLOBALS['hook_suffix']引用当前页的全局钩子后缀。参数(Parameters)参数类...

日期:2020-09-02 17:44:20 浏览:1071

customize_save_{$this->id_data[‘base’]}

do_action( "customize_save_{$this->id_data[‘base’]}", WP_Customize_Setting $this )动作钩子::在调用WP_Customize_Setting::save()方法时激发。Action Hook: Fires when the WP_Customize_Setting::save() method is called.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_data...

日期:2020-08-15 15:47:24 浏览:807

customize_value_{$this->id_data[‘base’]}

apply_filters( "customize_value_{$this->id_data[‘base’]}", mixed $default )过滤器::过滤未作为主题模式或选项处理的自定义设置值。Filter Hook: Filter a Customize setting value not handled as a theme_mod or option.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_date['base'],指的是设置...

日期:2020-08-15 15:47:24 浏览:900

get_comment_author_url

过滤钩子:过滤评论作者的URL。Filter Hook: Filters the comment author’s URL.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/comment-template.php:32610...

日期:2020-08-10 23:06:14 浏览:930

network_admin_edit_{$_GET[‘action’]}

do_action( "network_admin_edit_{$_GET[‘action’]}" )操作挂钩:启动请求的处理程序操作。Action Hook: Fires the requested handler action.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$u GET['action']引用请求的操作的名称。源码(Source)更新版本源码位置使用被使用3.1.0 wp-admin/network/edit.php:3600...

日期:2020-08-02 09:56:09 浏览:877

network_sites_updated_message_{$_GET[‘updated’]}

apply_filters( "network_sites_updated_message_{$_GET[‘updated’]}", string $msg )筛选器挂钩:在网络管理中筛选特定的非默认站点更新消息。Filter Hook: Filters a specific, non-default site-updated message in the Network admin.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分$_GET['updated']引用了非默认的...

日期:2020-08-02 09:56:03 浏览:864

pre_wp_is_site_initialized

过滤器::过滤在访问数据库之前是否初始化站点的检查。Filter Hook: Filters the check for whether a site is initialized before the database is accessed.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/ms-site.php:93910...

日期:2020-07-29 10:15:38 浏览:834

WordPress 的SEO 教学:如何在网站中加入关键字(Meta Keywords)与Meta 描述(Meta Description)?

你想在WordPress 中添加关键字和meta 描述吗?关键字和meta 描述使你能够提高网站的SEO。在本文中,我们将向你展示如何在WordPress 中正确添加关键字和meta 描述。为什么要在WordPress 中添加关键字和Meta 描述?关键字和说明让搜寻引擎更了解您的帖子和页面的内容。关键词是人们寻找您发布的内容时,可能会搜索的重要词语或片语。而Meta Description则是对你的页面和文章的简要描述。如果你想要了解更多关于中继标签的资讯,可以参考Google的说明。Meta 关键字和描...

日期:2020-10-03 21:18:25 浏览:1726

谷歌的SEO是什么

SEO (Search Engine Optimization)中文是搜寻引擎最佳化,意思近于「关键字自然排序」、「网站排名优化」。简言之,SEO是以搜索引擎(如Google、Bing)为曝光媒体的行销手法。例如搜寻「wordpress教学」,会看到本站的「WordPress教学:12个课程…」排行Google第一:关键字:wordpress教学、wordpress课程…若搜寻「网站架设」,则会看到另一个网页排名第1:关键字:网站架设、架站…以上两个网页,每月从搜寻引擎导入自然流量,达2万4千:每月「有机搜...

日期:2020-10-30 17:23:57 浏览:1308