C++ 如何在free()中检查恶魔般的狂野自由?

C++ 如何在free()中检查恶魔般的狂野自由?,c++,c,memory,C++,C,Memory,我对这种情况进行了测试: // Diabolical wild free #2. int main() { char* a = (char*) my_malloc(200); char* b = (char*) my_malloc(50); char* c = (char*) my_malloc(200); char* p = (char*) my_malloc(3000); (void) a, (void) c; memcpy(p, b - 200, 450); my_fre

我对这种情况进行了测试:

 // Diabolical wild free #2.

int main() {
 char* a = (char*) my_malloc(200);
 char* b = (char*) my_malloc(50);
 char* c = (char*) my_malloc(200);
 char* p = (char*) my_malloc(3000);
 (void) a, (void) c;
 memcpy(p, b - 200, 450);
 my_free(b);
 memcpy(b - 200, p, 450);
 my_free(b);
 m61_printstatistics();
}
预期结果:

/!内存错误:无效的自由指针

我现在可以使用free list检查第二次
free()
调用,但是

1) 第二个
free()
调用,释放另一个对象,因为
memcpy(b-200,p,450)

2) 在这种情况下,我们还对同一对象多次调用
free()
,但这是正确的执行

//正确的执行不应报告错误

int main() {
 for (int i = 0; i < 10; ++i)
 {
     int* ptr = (int*) my_malloc(sizeof(int) * 10);
     for (int j = 0; j < 10; ++j)
     {
         ptr[i] = i;
     }
     my_free(ptr);
 }
 m61_printstatistics();
 }
intmain(){
对于(int i=0;i<10;++i)
{
int*ptr=(int*)my_malloc(sizeof(int)*10);
对于(int j=0;j<10;++j)
{
ptr[i]=i;
}
我的免费(ptr);
}
m61_printstatistics();
}

那么如何在
free()
实现中检查无效的空闲指针呢?

您可以使用
xfree
宏进行测试(假设您的程序尚未
空闲(NULL)


在实践中,检查这类事情的最佳方法是使用运行它。您可以尝试创建自己的框架/宏,但通常最好将在valgrind下运行它作为定期测试过程的一部分。

假设我们忽略了在e由
b
指向的对象边界,您的目标是编写或测试一个C库,该库应该能够诊断
b
上对
free()
的双重调用的错误

这是一个错误的原因是
malloc
free
的典型实现将
free()
'd内存作为链表放入空闲内存列表中。为了节省内存,只需
free()
'd内存本身被重用为自由列表数据结构的节点对象。因此,自由列表中的其他一些节点可能在第一次调用
free()
后指向由
b
表示的内存。在第二次调用
free()时
调用时,
b
的节点将再次插入到列表中,可能会导致其他节点指向它。空闲列表将被视为已损坏。由于
malloc()
从空闲列表中删除数据,因此在空闲列表中两次使用同一节点将是一个严重问题


有几种方法可以“捕获”这个问题。一种可能是将空闲列表实现为一个查找树,它使用自己的内存来查找指向返回到
free()
的内存的节点。这允许第二次调用
free()
注意到
b
已经在树中。因此,对
free()
的双重调用被检测到,并且可以相应地进行标记。

调用
free()
后,可以将指针设置为
NULL
,这将进行第二次调用
free()
非操作调用
free()
对已被释放的对象执行未定义的行为。
free
执行超出您(有效)访问权限的操作。您不能两次释放同一块。...........这必须是以前调用malloc()、calloc()或realloc()返回的。否则,或者如果是free(ptr)已经被调用过,未定义的行为发生。“@NathanOliver这不起作用。因为我们
memcpy(b-200,p,450)
所有数据都将被删除顺便说一句,第二个memcpy也是完全未定义的行为。释放内存后,您不能触摸它。@Anatoly您似乎认为memcpy会物理移动物理内存块(或等效的虚拟内存块)。它不是。它要求您对源内存块和目标内存块都有权限。您完全有责任确保满足此要求,但您在代码中公然违反了此要求。这是一个严重的错误。当我第二次释放内存时,我会触摸另一个内存块!因为memcpy(b-200,p,450)这就是为什么自由列表需要作为一个单独的数据结构来实现,该结构指向被释放的元素。您的测试旨在销毁通常用于将被释放的元素存储在自由列表中的“节点”数据。
#if MY_DEBUG
#define xfree(p) ((void) ((p) ? (free(p), (p) = 0) : (fprintf(stderr, "double free\n"), exit(1), (void *) 0)))
#else
#define xfree(p)  free(p)
#endif