Report the offending pointer on sized dealloc bug detection.

This commit is contained in:
Qi Wang 2021-02-05 16:47:09 -08:00 committed by Qi Wang
parent edbfe6912c
commit f3b2668b32
5 changed files with 31 additions and 14 deletions

View File

@ -211,7 +211,7 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
} }
JEMALLOC_ALWAYS_INLINE bool JEMALLOC_ALWAYS_INLINE bool
large_dalloc_safety_checks(edata_t *edata, szind_t szind) { large_dalloc_safety_checks(edata_t *edata, void *ptr, szind_t szind) {
if (!config_opt_safety_checks) { if (!config_opt_safety_checks) {
return false; return false;
} }
@ -229,7 +229,8 @@ large_dalloc_safety_checks(edata_t *edata, szind_t szind) {
return true; return true;
} }
if (unlikely(sz_index2size(szind) != edata_usize_get(edata))) { if (unlikely(sz_index2size(szind) != edata_usize_get(edata))) {
safety_check_fail_sized_dealloc(/* current_dealloc */ true); safety_check_fail_sized_dealloc(/* current_dealloc */ true,
ptr);
return true; return true;
} }
@ -243,7 +244,7 @@ arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind) {
} else { } else {
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
ptr); ptr);
if (large_dalloc_safety_checks(edata, szind)) { if (large_dalloc_safety_checks(edata, ptr, szind)) {
/* See the comment in isfree. */ /* See the comment in isfree. */
return; return;
} }
@ -287,7 +288,7 @@ arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
} else { } else {
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
ptr); ptr);
if (large_dalloc_safety_checks(edata, szind)) { if (large_dalloc_safety_checks(edata, ptr, szind)) {
/* See the comment in isfree. */ /* See the comment in isfree. */
return; return;
} }

View File

@ -1,7 +1,7 @@
#ifndef JEMALLOC_INTERNAL_SAFETY_CHECK_H #ifndef JEMALLOC_INTERNAL_SAFETY_CHECK_H
#define JEMALLOC_INTERNAL_SAFETY_CHECK_H #define JEMALLOC_INTERNAL_SAFETY_CHECK_H
void safety_check_fail_sized_dealloc(bool current_dealloc); void safety_check_fail_sized_dealloc(bool current_dealloc, const void *ptr);
void safety_check_fail(const char *format, ...); void safety_check_fail(const char *format, ...);
/* Can set to NULL for a default. */ /* Can set to NULL for a default. */
void safety_check_set_abort(void (*abort_fn)(const char *)); void safety_check_set_abort(void (*abort_fn)(const char *));

View File

@ -2751,7 +2751,7 @@ maybe_check_alloc_ctx(tsd_t *tsd, void *ptr, emap_alloc_ctx_t *alloc_ctx) {
&dbg_ctx); &dbg_ctx);
if (alloc_ctx->szind != dbg_ctx.szind) { if (alloc_ctx->szind != dbg_ctx.szind) {
safety_check_fail_sized_dealloc( safety_check_fail_sized_dealloc(
/* current_dealloc */ true); /* current_dealloc */ true, ptr);
return true; return true;
} }
if (alloc_ctx->slab != dbg_ctx.slab) { if (alloc_ctx->slab != dbg_ctx.slab) {
@ -2801,7 +2801,8 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) {
if (config_opt_safety_checks) { if (config_opt_safety_checks) {
/* Small alloc may have !slab (sampled). */ /* Small alloc may have !slab (sampled). */
if (alloc_ctx.szind != sz_size2index(usize)) { if (alloc_ctx.szind != sz_size2index(usize)) {
safety_check_fail_sized_dealloc(true); safety_check_fail_sized_dealloc(true,
ptr);
} }
} }
} else { } else {

View File

@ -3,14 +3,14 @@
static void (*safety_check_abort)(const char *message); static void (*safety_check_abort)(const char *message);
void safety_check_fail_sized_dealloc(bool current_dealloc) { void safety_check_fail_sized_dealloc(bool current_dealloc, const void *ptr) {
char *src = current_dealloc ? "the current pointer being freed" : char *src = current_dealloc ? "the current pointer being freed" :
"in thread cache, possibly from previous deallocations"; "in thread cache, possibly from previous deallocations";
safety_check_fail("<jemalloc>: size mismatch detected, likely caused by" safety_check_fail("<jemalloc>: size mismatch detected, likely caused by"
" application sized deallocation bugs (source: %s). Suggest building" " application sized deallocation bugs (source address: %p, %s). "
"with --enable-debug or address sanitizer for debugging. Abort.\n", "Suggest building with --enable-debug or address sanitizer for "
src); "debugging. Abort.\n", ptr, src);
} }
void safety_check_set_abort(void (*abort_fn)(const char *)) { void safety_check_set_abort(void (*abort_fn)(const char *)) {

View File

@ -250,6 +250,20 @@ tcache_bin_flush_metadata_visitor(void *szind_sum_ctx,
util_prefetch_write_range(alloc_ctx->edata, sizeof(edata_t)); util_prefetch_write_range(alloc_ctx->edata, sizeof(edata_t));
} }
JEMALLOC_NOINLINE static void
tcache_bin_flush_size_check_fail(cache_bin_ptr_array_t *arr, szind_t szind,
size_t nptrs, emap_batch_lookup_result_t *edatas) {
bool found_mismatch = false;
for (size_t i = 0; i < nptrs; i++) {
if (edata_szind_get(edatas[i].edata) != szind) {
found_mismatch = true;
safety_check_fail_sized_dealloc(false,
tcache_bin_flush_ptr_getter(arr, i));
}
}
assert(found_mismatch);
}
static void static void
tcache_bin_flush_edatas_lookup(tsd_t *tsd, cache_bin_ptr_array_t *arr, tcache_bin_flush_edatas_lookup(tsd_t *tsd, cache_bin_ptr_array_t *arr,
szind_t binind, size_t nflush, emap_batch_lookup_result_t *edatas) { szind_t binind, size_t nflush, emap_batch_lookup_result_t *edatas) {
@ -264,8 +278,8 @@ tcache_bin_flush_edatas_lookup(tsd_t *tsd, cache_bin_ptr_array_t *arr,
&tcache_bin_flush_ptr_getter, (void *)arr, &tcache_bin_flush_ptr_getter, (void *)arr,
&tcache_bin_flush_metadata_visitor, (void *)&szind_sum, &tcache_bin_flush_metadata_visitor, (void *)&szind_sum,
edatas); edatas);
if (config_opt_safety_checks && szind_sum != 0) { if (config_opt_safety_checks && unlikely(szind_sum != 0)) {
safety_check_fail_sized_dealloc(false); tcache_bin_flush_size_check_fail(arr, binind, nflush, edatas);
} }
} }
@ -435,7 +449,8 @@ tcache_bin_flush_impl(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
dalloc_count++; dalloc_count++;
} }
} else { } else {
if (large_dalloc_safety_checks(edata, binind)) { if (large_dalloc_safety_checks(edata, ptr,
binind)) {
/* See the comment in isfree. */ /* See the comment in isfree. */
continue; continue;
} }