如何在free()中检查恶魔般的狂野自由
How check diabolical wild free in free()?
我有一个针对这种情况的测试:
// 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()
实现中检查无效的指针释放呢?
让我们假设我们忽略了在b
所指向的对象边界之外进行读取和写入所导致的明显的未定义行为,并且您的预期目的是编写或测试一个C库,该库应该能够诊断b
上对free()
的双重调用的错误。
这是一个错误的原因是malloc
和free
的典型实现会将free()
'd内存作为链表放入空闲内存列表中。作为节省内存的一种方式,仅free()
'd内存本身被重新用作空闲列表数据结构的节点对象。因此,空闲列表中的某个其他节点可能在第一个free()
调用之后指向由b
表示的存储器。在第二次调用free()
时,b
的节点将再次插入到列表中,可能会导致另一个节点指向它。空闲列表将被视为已损坏。由于malloc()
从空闲列表中删除数据,因此在空闲列表中有两次相同的节点将是一个严重的问题。
有几种方法可以"抓住"这个问题。一种可能性是,空闲列表被实现为查找树,该查找树将其自己的内存用于指向返回到free()
的内存的节点。这允许对free()
的第二次调用注意到b
已经在树中。因此,对free()
的双重呼叫被检测到并且可以被相应地标记。
在实践中,检查这类事情的最佳方法是使用valgrind运行它。您可以尝试创建自己的框架/宏,但通常最好将在valgrind下运行它作为定期测试过程的一部分。
您可以使用xfree
宏进行测试(假设您的程序还没有free(NULL)
:
#if MY_DEBUG
#define xfree(p) ((void) ((p) ? (free(p), (p) = 0) : (fprintf(stderr, "double freen"), exit(1), (void *) 0)))
#else
#define xfree(p) free(p)
#endif
- valgrind-hellgrind与泄漏检查的结果不同
- C++模板来检查友元函数的存在
- 检查输入是否不是整数或数字
- 试图让变量检查数组中的某些内容
- 检查值是否在集合p1和p2中,但不在p3中
- C++概念:如何使用'concept'检查模板化结构的属性?
- 概念TS检查忽略私有访问修饰符
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- 如何在C++中检查2D数组中负值的输入验证
- C++:正在检查LinkedList中的回文-递归方法-错误
- 使用for循环检查数组中的重复项
- 如何检查一个c++字符串中有多少相同的字符/数字
- 检查不带转换的扫描格式
- 如何检查线程是否锁定
- 清除前检查矢量
- 如何处理来自核心指南检查器的关于gsl::at的静态分析警告
- C++LDAP检查用户是否是特定组的成员
- 检查TCHAR数组输入是否为带符号整数C++
- 如何在free()中检查恶魔般的狂野自由