以下程序不会触发断言失败:
int main(int argc, char **argv)
{
int * n = (int *)malloc(100);
//malloc_stats_print(nullptr, nullptr, "gablh");
free(n);
*n += 1;
std::cerr << *n << std::endl;
for (int i = 0; i != 10; ++i) {
std::cerr << *(n+i) << std::endl;
}
}
当我运行程序时
MALLOC_CONF="quarantine:32,abort:true,stats_print:true" ex_stats_pr
我明白了:
1515870811
1515870811
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
1515870810
有没有办法用jemalloc触发中止失败?
答案 0 :(得分:0)
这不是你问题的直接答案,但是......
未定义未定义的行为。释放已经被释放的记忆落入了这个阵营。根据您的内存处理程序的实现,您可能有一个“验证内存”类型函数,它沿着您的空闲内存列表查看是否存在某种类型的损坏,但即使这样也不会捕获所有内容(不是我特别熟悉jemalloc
)。可能是你的上面的代码击中了没有人关心的内存,因此不会被抓住。哎呀,你的std::cerr
语句也在做未定义的行为,所以你甚至不能相信它的值(想想线程和操作系统抓取和改变内存等)。
这是您尽可能不直接在C ++中使用指针的原因之一。管理生命周期的智能指针和容器会自动防止几乎所有这些类型的错误。
答案 1 :(得分:0)
你希望jemalloc检测到一次写入释放的内存和一些读取释放的内存。
但是jemalloc库没有这个功能。其调试模式仅检测导致内存损坏的一组有限错误。例如双重释放。
这不是一个任意限制,因为像jemalloc这样的库只是无法检测到任何类型的内存访问错误。这意味着作为一个库,它可以轻松地重载malloc()/ free()等并安装一个退出处理程序。因此,调试模式实现可以有效地实现有限的一组检查。当然,每个调试模式实现都会选择自己的权衡。例如,jemalloc在free期间也没有检测到简单的缓冲区溢出,尽管其他具有调试功能的库(例如Solaris'libumem)实现了一种轻量级机制,其中检查了一些特殊尾随字节的完整性。
对于像jemalloc这样的库来检测读取/写入释放的内存,它必须将调试器样式的监视安装到每个释放的区域中,这样会安静复杂并产生大量的运行时开销 - 如果这会扩展到许多大型分配,一点都不。
重点是:jemalloc是检测释放内存(A)和释放内存(B)的错误工具。
例如,GCC和Clang附带的Address Sanitizer(-fsanitize=address
)能够检测到(A),但不能检测到(B)。并且Valgrind(valgrind --tool=memcheck
)能够检测(A)和(B)并将这些问题报告为无效读/写到释放块中。这两个工具肯定比分配器库的简单调试模式具有更高的运行时开销。而且由于valgrind的方法是模拟CPU,其开销远高于Address Sanitizer。