+-
c – 为什么两次调用时会发生自由崩溃?
在C和C中,free(my_pointer)在被调用两次时崩溃.

为什么?每个malloc都有大小的簿记.当第一个free被调用时,它会识别出这个被分配的大小,这就是为什么我们不需要通过大小和免费调用.

因为它知道每件事为什么不检查第二次并且什么都不做?

我不明白malloc / free行为或free是不安全实现的.

最佳答案
你不允许在未分配的内存上免费拨打电话,标准明确指出(略微转述,我的重点):

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块头的东西,会发生什么?喜欢:

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

混乱,那是什么.

内存分配功能就像电锯一样,如果你正确使用它们,你应该没有问题.但是,如果你滥用它们,后果是你自己的错,无论是破坏记忆还是更糟,或者切断你的一只手:-)

关于评论:

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

如果没有保留所有malloc和免费通话的记录以确保你没有双重禁用一块,我不能认为这是可行的.这将需要巨大的开销,仍然无法解决所有问题.

如果:

> thread在地址42处分配和释放的内存.
>线程B为内存分配了一个地址42并开始使用它.
>线程A第二次释放该内存.
>线程C为内存分配了一个地址42并开始使用它.

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

不,我认为当前的malloc和free都可以正常使用它们.无论如何都要考虑实现自己的版本,我认为没有错,但我怀疑你会遇到一些非常棘手的性能问题.

如果你想要免费实现自己的包装器,你可以使它更安全(以牺牲性能为代价),特别是下面的myFreeXxx调用:

#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,它将同时:

>释放记忆;和
>将指针设置为NULL.

后一位意味着,如果你试图再次释放指针,它将什么都不做(因为标准特别涵盖了释放NULL).

它不会保护您免受所有情况的影响,例如,如果您将指针的副本复制到别处,则释放原始文件,然后释放副本:

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

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

#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,它将根据类型选择正确的函数.

点击查看更多相关文章

转载注明原文:c – 为什么两次调用时会发生自由崩溃? - 乐贴网