为什么两次调用时会发生自由崩溃? [英] Why does free crash when called twice?

查看:124
本文介绍了为什么两次调用时会发生自由崩溃?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C和C ++中,两次调用 free(my_pointer)时会崩溃。

In C and C++, free(my_pointer) crashes when it is called twice.

为什么?每个 malloc 都有大小记帐。当第一个免费被调用时,它会识别出已分配了什么大小,这就是为什么我们不需要随免费通话传递大小的原因。

Why? There is bookkeeping of every malloc along with the size. When the first free is called then it identifies that this was allocated with what size that's why we need not to pass size along with free call.

因为它知道每件事,为什么它第二次不检查又什么也不做?

Since it knows every thing why doesn't it check the second time around and do nothing?

我不理解 malloc / free 行为或 free 行为无法安全实施。

Either I don't understand malloc/free behavior or free is not safely implemented.

推荐答案

不允许您在未分配的内存上调用免费,标准明确指出(我稍作解释):

You are not allowed to call free on unallocated memory, the standard states that quite clearly (slightly paraphrased, my emphasis):


free 函数导致其参数所指向的空间被释放,即,可供进一步分配。如果参数为空指针,则不执行任何操作。否则,如果参数与内存管理函数先前返回的指针不匹配,或者 如果已通过调用free或realloc释放空间,则行为不确定。

The free function causes the space pointed to by its argument to be deallocated, that is, made available for further allocation. If the argument is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

会发生什么情况,例如,如果您要双重释放的地址已重新分配到新块的中间分配它的代码恰好在那儿存储了看起来像真正的malloc-block标头的东西?像这样:

What happens, for example, if the address you're double-freeing has been reallocated in the middle of a new block and the code that allocated it just happened to store something there that looked like a real malloc-block header? Like:

 +- New pointer    +- Old pointer
 v                 v
+------------------------------------+
|                  <Dodgy bit>       |
+------------------------------------+

就是这样。

内存分配功能就像电锯,并且,如果您正确使用它们,则应该没有问题。但是,如果您滥用它们,后果将是您自己的错,要么是内存损坏,要么更糟,或者是切断您的一只手:-)

Memory allocation functions are a tool just like a chainsaw and, provided you use them correctly, you should have no problems. If you misuse them, however, the consequences are your own fault, either corrupting memory or worse, or cutting off one of your arms :-)

关于注释:


...它可以与最终用户优雅地交流有关将同一位置加倍免费的信息。

... it can communicate gracefully to enduser about the doubling free the same location.

保留所有 malloc free 调用以确保您不会两次释放一个块,我认为这不可行。这将需要大量的开销,而 still 并不能解决所有问题。

Short of keeping a record of all malloc and free calls to ensure you don't double-free a block, I can't see this as being workable. It would require a huge overhead and still wouldn't fix all the problems.

如果发生以下情况,将会发生什么:

What would happen if:


  • 线程A在地址42分配并释放了内存。

  • 线程B在地址42分配了内存并开始使用它。

  • 线程A再次释放了内存。

  • 线程C为内存分配了地址42,并开始使用它。

  • thread A allocated and freed memory at address 42.
  • thread B allocated memory a address 42 and started using it.
  • thread A freed that memory a second time.
  • thread C allocated memory a address 42 and started using it.

然后,线程B和C都认为它们拥有该内存(这些不必是执行线程,我在这里使用术语线程一段正在运行的代码-可能全部在一个执行线程中,但按顺序调用。)

You then have threads B and C both thinking they own that memory (these don't have to be threads of execution, I'm using the term thread here as just a piece of code that runs - it could all be in the one thread of execution but called sequentially).

不,我认为当前的 malloc 免费很好,只要您正确使用它们即可。一定考虑一下实现自己的版本,我认为这没什么问题,但我怀疑您会遇到一些非常棘手的性能问题。

No, I think the current malloc and free are just fine provided you use them properly. By all means give some thought to implementing your own version, I see nothing wrong with that but I suspect you'll run into some pretty thorny performance issues.

如果您要做要围绕免费实现自己的包装器,则可以使其更安全(以对性能的影响不大),特别是类似于下面的 myFreeXxx 调用:

If you do want to implement your own wrapper around free, you can make it safer (at the cost of a little performance hit), specifically with something like the myFreeXxx calls below:

#include <stdio.h>
#include <stdlib.h>

void myFreeVoid (void **p) { free (*p); *p = NULL; }
void myFreeInt  (int  **p) { free (*p); *p = NULL; }
void myFreeChar (char **p) { free (*p); *p = NULL; }

int main (void) {
    char *x = malloc (1000);
    printf ("Before: %p\n", x);
    myFreeChar (&x);
    printf ("After:  %p\n", x);
    return 0;
}

代码的结果是您可以调用 myFreeXxx ,并带有指向您的指针的指针,

The upshot of the code is that you can call myFreeXxx with a pointer to your pointer and it will both:


  • 释放内存;

  • 将指针设置为NULL。

后一点表示,如果您尝试再次释放指针,将不会执行任何操作(因为标准专门涵盖了释放NULL)。

That latter bit means that, if you try to free the pointer again, it will do nothing (because freeing NULL is specifically covered by the standard).

不会保护您在所有情况下(例如,如果您在其他地方制作了指针的副本),请释放原始副本,然后释放副本:

It won't protect you from all situations, such as if you make a copy of the pointer elsewhere, free the original, then free the copy:

char *newptr = oldptr;
myFreeChar (&oldptr);     // frees and sets to NULL.
myFreeChar (&newptr);     // double-free because it wasn't set to NULL.






如果您要使用C11,可以使用既然C具有编译时函数重载,那么比必须为每种类型显式调用不同的函数更好的方法。您可以使用通用选择来调用正确的函数,同时仍然允许类型安全:


If you're up to using C11, there's a better way than having to explicitly call a different function for each type now that C has compile time function overloading. You can use generic selections to call the correct function while still allowing for type safety:

#include <stdio.h>
#include <stdlib.h>

void myFreeVoid (void **p) { free (*p); *p = NULL; }
void myFreeInt  (int  **p) { free (*p); *p = NULL; }
void myFreeChar (char **p) { free (*p); *p = NULL; }
#define myFree(x) _Generic((x), \
    int** :  myFreeInt,  \
    char**:  myFreeChar, \
    default: myFreeVoid  )(x)

int main (void) {
    char *x = malloc (1000);
    printf ("Before: %p\n", x);
    myFree (&x);
    printf ("After:  %p\n", x);
    return 0;
}

这样,您只需调用 myFree ,它将根据类型选择正确的函数。

With that, you simply call myFree and it will select the correct function based on the type.

这篇关于为什么两次调用时会发生自由崩溃?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆