Realloc: Make behavior of realloc(ptr, 0) configurable.

This commit is contained in:
David T. Goldblatt
2019-09-23 17:56:19 -07:00
committed by David Goldblatt
parent ee961c2310
commit 9cfa805947
15 changed files with 256 additions and 26 deletions

View File

@@ -112,6 +112,7 @@ CTL_PROTO(opt_prof_gdump)
CTL_PROTO(opt_prof_final)
CTL_PROTO(opt_prof_leak)
CTL_PROTO(opt_prof_accum)
CTL_PROTO(opt_zero_realloc)
CTL_PROTO(tcache_create)
CTL_PROTO(tcache_flush)
CTL_PROTO(tcache_destroy)
@@ -339,7 +340,8 @@ static const ctl_named_node_t opt_node[] = {
{NAME("prof_gdump"), CTL(opt_prof_gdump)},
{NAME("prof_final"), CTL(opt_prof_final)},
{NAME("prof_leak"), CTL(opt_prof_leak)},
{NAME("prof_accum"), CTL(opt_prof_accum)}
{NAME("prof_accum"), CTL(opt_prof_accum)},
{NAME("zero_realloc"), CTL(opt_zero_realloc)}
};
static const ctl_named_node_t tcache_node[] = {
@@ -1793,6 +1795,8 @@ CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
CTL_RO_NL_GEN(opt_zero_realloc,
zero_realloc_mode_names[opt_zero_realloc_action], const char *)
/******************************************************************************/

View File

@@ -67,6 +67,15 @@ bool opt_junk_free =
#endif
;
zero_realloc_action_t opt_zero_realloc_action =
zero_realloc_action_strict;
const char *zero_realloc_mode_names[] = {
"strict",
"free",
"abort",
};
bool opt_utrace = false;
bool opt_xmalloc = false;
bool opt_zero = false;
@@ -1411,6 +1420,22 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
}
CONF_CONTINUE;
}
if (CONF_MATCH("zero_realloc")) {
if (CONF_MATCH_VALUE("strict")) {
opt_zero_realloc_action
= zero_realloc_action_strict;
} else if (CONF_MATCH_VALUE("free")) {
opt_zero_realloc_action
= zero_realloc_action_free;
} else if (CONF_MATCH_VALUE("abort")) {
opt_zero_realloc_action
= zero_realloc_action_abort;
} else {
CONF_ERROR("Invalid conf value",
k, klen, v, vlen);
}
CONF_CONTINUE;
}
CONF_ERROR("Invalid conf pair", k, klen, v, vlen);
#undef CONF_ERROR
#undef CONF_CONTINUE
@@ -3133,18 +3158,17 @@ je_rallocx(void *ptr, size_t size, int flags) {
return ret;
}
JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
void JEMALLOC_NOTHROW *
JEMALLOC_ALLOC_SIZE(2)
je_realloc(void *ptr, size_t size) {
LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
if (likely(ptr != NULL && size != 0)) {
void *ret = do_rallocx(ptr, size, 0, true);
LOG("core.realloc.exit", "result: %p", ret);
return ret;
} else if (ptr != NULL && size == 0) {
/* realloc(ptr, 0) is equivalent to free(ptr). */
static void *
do_realloc_nonnull_zero(void *ptr) {
if (opt_zero_realloc_action == zero_realloc_action_strict) {
/*
* The user might have gotten a strict setting while expecting a
* free setting. If that's the case, we at least try to
* reduce the harm, and turn off the tcache while allocating, so
* that we'll get a true first fit.
*/
return do_rallocx(ptr, 1, MALLOCX_TCACHE_NONE, true);
} else if (opt_zero_realloc_action == zero_realloc_action_free) {
UTRACE(ptr, 0, 0);
tcache_t *tcache;
tsd_t *tsd = tsd_fetch();
@@ -3156,14 +3180,39 @@ je_realloc(void *ptr, size_t size) {
tcache = NULL;
}
uintptr_t args[3] = {(uintptr_t)ptr, size};
uintptr_t args[3] = {(uintptr_t)ptr, 0};
hook_invoke_dalloc(hook_dalloc_realloc, ptr, args);
ifree(tsd, ptr, tcache, true);
check_entry_exit_locking(tsd_tsdn(tsd));
LOG("core.realloc.exit", "result: %p", NULL);
return NULL;
} else {
safety_check_fail("Called realloc(non-null-ptr, 0) with "
"zero_realloc:abort set\n");
/* In real code, this will never run; the safety check failure
* will call abort. In the unit test, we just want to bail out
* without corrupting internal state that the test needs to
* finish.
*/
return NULL;
}
}
JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
void JEMALLOC_NOTHROW *
JEMALLOC_ALLOC_SIZE(2)
je_realloc(void *ptr, size_t size) {
LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
if (likely(ptr != NULL && size != 0)) {
void *ret = do_rallocx(ptr, size, 0, true);
LOG("core.realloc.exit", "result: %p", ret);
return ret;
} else if (ptr != NULL && size == 0) {
void *ret = do_realloc_nonnull_zero(ptr);
LOG("core.realloc.exit", "result: %p", ret);
return ret;
} else {
/* realloc(NULL, size) is equivalent to malloc(size). */
void *ret;

View File

@@ -1109,6 +1109,7 @@ stats_general_print(emitter_t *emitter) {
OPT_WRITE_BOOL("prof_leak")
OPT_WRITE_BOOL("stats_print")
OPT_WRITE_CHAR_P("stats_print_opts")
OPT_WRITE_CHAR_P("zero_realloc")
emitter_dict_end(emitter);