如何在free()中检查恶魔狂野免费?

时间:2015-04-30 17:20:22

标签: 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_free(b);
 memcpy(b - 200, p, 450);
 my_free(b);
 m61_printstatistics();
}

预期结果:

  

//! MEMORY BUG: invalid free of pointer

我现在可以使用免费列表查看第二个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();
 }

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

3 个答案:

答案 0 :(得分:3)

让我们假设我们忽略了由b指向的对象边界之外的读写造成的明显的未定义行为,并且您的预期目的是编写或测试假设的C库能够诊断free()b双重呼叫的错误。

这是一个错误的原因是mallocfree的典型实现会将free()内存作为链接列表放入空闲内存列表中。作为节省内存的一种方式,仅free()内存本身被重用作空闲列表数据结构的节点对象。因此,空闲列表中的一些其他节点可能在第一次b呼叫之后指向由free()表示的存储器。在第二次free()调用时,b的节点将再次插入列表中,可能导致不同的节点指向它。免费列表将被视为已损坏。由于malloc()从空闲列表中删除数据,因此在空闲列表中两次使用相同的节点将是一个严重的问题。

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

答案 1 :(得分:1)

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

#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

答案 2 :(得分:1)

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