无法理解为什么释放内存会引发错误

时间:2017-03-15 04:56:41

标签: c pointers malloc free

我正在读Dangling Pointer并发现这是一个好习惯,以防止自己悬挂指针错误。

free(ptr); // free the ptr
ptr = NULL; 

现在我决定使用示例vanilla C代码测试它。

CASE_1

char *ptr = malloc(10);
... 
...
free(ptr); 
ptr=NULL;
// Just to check what happen if I call free more than I once
free(ptr)
ptr=NULL;

一切正常。直到我决定将free和指针NULL赋值包装在function中,我将其命名为safefree

void safefree(char *pp) {
  free(pp);
  pp = NULL;
}

CASE_2

现在,当我运行上述方法超过1(像这样)

safefree(ptr);

safefree(ptr);

我收到以下错误。

malloc: *** error for object 0x7fd98f402910: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

我碰巧理解错误(没有分配被释放的指针) 但是我不明白为什么它在 CASE_1 中没有失败,并且在示例代码的后半部分失败了。

2 个答案:

答案 0 :(得分:5)

首先,让我们回顾一下free()的行为。引用C11,章节§7.22.3.3

void free(void *ptr);
     

free函数导致ptr指向的空间被释放,即   可供进一步分配。 如果ptr是空指针,则不执行任何操作。否则,如果   该参数与先前由内存管理返回的指针不匹配   函数,或者如果通过调用freerealloc释放了空格,   行为未定义。

遵循两个强调要点。

  • 您可以根据需要多次将空指针NULL传递给free(),它们是有效的调用(只是被忽略)。
  • 您无法传递已经传递给free()一次的指针。

案例1:

此处,在使用指针调用free()后,我们显式将指针设置为NULL。这就是为什么,稍后用相同的指针变量调用free(),任何时间,都不是问题。

案例2:

C使用pass-by-value进行函数参数传递。这就是为什么,当包裹在一个函数中时,

free(pp);

按预期工作,(它将所需指针传递给free())但

pp = NULL;

是函数的本地函数,并且该更改不会反映给调用者。因此,再次调用该函数会导致双重释放,就像现在一样,

  • 指针已传递给free()
  • 分配的NULL未反映给调用者,因此指针未设置为NULL
  • 在下次通话中,我们已经再次通过了free() d指针。

如前所述,这会调用undefined behavior

解决方案:您需要将指针作为被调用函数safefree()的参数传递给指针,并且可以从被调用函数中将指针值设置为{{1}将它反映在调用者中。像

这样的东西
NULL

并且呼叫

void safefree(void ** ptrToPtr) 
{ 
     free(*ptrToPtr); 
     *ptrToPtr= NULL; 
 }

将完成这项工作(注意那里的类型,无论如何)。

答案 1 :(得分:1)

除了Jonathan的评论之外,如果你做了导致未定义行为的事情(再次释放指针),会导致未定义的行为(错误,崩溃)。

在不同的上下文中执行相同的操作并不一定会导致相同的未定义的行为,这取决于实现细节;它们通常只为编译器开发人员所知,因此它们看起来是随机的'从外部。通过分析随机未定义的行为,无法学到任何东西。例如,编译时可能影响结果......,或者你工作的目录的拼写......任何东西。