jemalloc未检测到内存损坏

jemalloc not detecting memory corruption

本文关键字:内存 损坏 检测 jemalloc      更新时间:2023-10-16

以下程序不会触发断言失败:

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触发中止失败?

这不是对您问题的直接回答,但。。。

未定义的行为是未定义的。与被解放的记忆玩耍属于这个阵营。根据您的内存处理程序的实现,您可能有一个"验证内存"类型的函数,该函数会在空闲内存列表中遍历,以查看是否存在某种损坏,但即使这样也无法捕获所有内容(我不熟悉jemalloc,尤其是我自己)。这可能是因为你上面的代码命中了没有人关心的内存,所以不会被捕获。见鬼,你的std::cerr语句也在做未定义的行为,所以你甚至不能相信它的值(想想线程和操作系统抓取和更改内存等)

这也是您不在C++中尽可能直接使用指针的原因之一。管理生存期的智能指针和容器可以自动防止几乎所有这些类型的错误。

您期望jemalloc检测到一次写入释放内存和一些读取释放内存。

但是jemalloc库没有这个功能。它的调试模式只检测到一组有限的错误,这些错误会导致内存损坏。例如,两次释放。

这不是一个任意的限制,因为像jemalloc这样的库无法检测任何类型的内存访问错误。这意味着作为一个库,它可以很容易地重载malloc()/free()等并安装一个退出处理程序。因此,调试模式实现可以有效地实现有限的一组检查。当然,每个调试模式的实现都有自己的取舍。例如,jemalloc在空闲期间也不会检测到简单的缓冲区溢出,尽管其他具有调试功能的库(例如Solaris的libumem)实现了一种轻量级机制,在该机制中检查一些特殊尾随字节的完整性。

对于像jemalloc这样的库来说,要检测对释放内存的读/写,就必须在每个释放区域中安装调试器风格的监视,这将非常复杂,并产生大量的运行时开销——如果这会扩展到大量的分配的话。

重点是:jemalloc是错误的工具,用于检测对释放内存(A)的写入和对释放内存的读取。

例如,GCC和Clang附带的地址消毒器(-fsanitize=address)能够检测(A),但不能检测(B)。Valgrind(valgrind --tool=memcheck)能够检测(A)和(B),并将这些问题报告为对释放块的无效读/写。与分配器库的简单调试模式相比,这两种工具的运行时开销肯定更高。由于valgrind的方法是模拟CPU,因此其开销远高于Address Sanitizer的开销。