1

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

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

4

2 回答 2

0

这不是您问题的直接答案,但是...

未定义的行为是未定义的。玩弄被释放的记忆就属于这个阵营。根据您的内存处理程序的实现,您可能有一个“验证内存”类型的函数,它沿着您的空闲内存列表查看是否存在某种损坏,但即使这样也不会捕获所有内容(不是特别熟悉jemalloc我自己)。可能是您上面的代码碰到了没人关心的内存,因此不会被抓住。哎呀,您的std::cerr语句也在做未定义的行为,所以您甚至不能相信它的值(想想线程和操作系统抓取和更改内存等)

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

于 2016-06-09T17:26:23.980 回答
0

您希望 jemalloc 检测到对已释放内存的写入和对已释放内存的一些读取。

但是 jemalloc 库没有这个能力。它的调试模式只检测有限的一组导致内存损坏的错误。例如双释放。

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

对于像 jemalloc 这样的库来检测对释放内存的读/写,它必须在每个释放的区域中安装调试器样式的监视程序,这将非常复杂并产生显着的运行时开销——如果这可以扩展到许多和大型分配的话。

关键是:jemalloc 是检测写入已释放内存 (A) 和读取已释放内存 (B) 的错误工具。

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

于 2017-09-16T20:50:08.900 回答