You expect that jemalloc detects one write into freed memory and some reads of freed memory.
But the jemalloc library doesn't have this capability. Its debug mode only detects a limited set of errors that lead to memory corruption. For example double-frees.
This isn't an arbitrary limitation, as a library like jemalloc just can't detect any kind of memory access error. That means as a library, it can easily overload malloc()/free() etc. and install an exit handler. A debug mode implementation thus can effectively implement a limited set of checks. And of course, each debug mode implementation chooses its own trade-offs. For example, jemalloc also doesn't detect simple buffer-overflows during free although other libraries with debugging capabilities (e.g. Solaris' libumem) implement a lightweight mechanism where the integrity of some special trailing bytes is checked.
For a library like jemalloc to detect reads/writes into freed memory it would have to install debugger-style watches into each freed region which would be quiet complicated and yield significant runtime overhead - if that would scale for many and large allocations, at all.
The point is: jemalloc is the wrong tool for detecting writes into freed memory (A) and reads of freed memory (B).
For example, the Address Sanitizer (-fsanitize=address
) that comes with GCC and Clang is able to detect (A), but not (B). And Valgrind (valgrind --tool=memcheck
) is able to detect both (A) and (B) and reports those issues as invalid reads/write into a freed block. Both tools certainly have higher runtime overhead than a simple debugging mode of a allocator library. And since valgrind's approach is to emulate a CPU its overhead is much higher than the one of Address Sanitizer.