Add prof_leak_error option
The option makes the process to exit with error code 1 if a memory leak is detected. This is useful for implementing automated tools that rely on leak detection.
This commit is contained in:
parent
eafd2ac39f
commit
b798fabdf7
@ -1553,6 +1553,25 @@ malloc_conf = "xmalloc:true";]]></programlisting>
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.prof_leak_error">
|
||||
<term>
|
||||
<mallctl>opt.prof_leak_error</mallctl>
|
||||
(<type>bool</type>)
|
||||
<literal>r-</literal>
|
||||
[<option>--enable-prof</option>]
|
||||
</term>
|
||||
<listitem><para>Similar to <link linkend="opt.prof_leak"><mallctl>
|
||||
opt.prof_leak</mallctl></link>, but makes the process exit with error
|
||||
code 1 if a memory leak is detected. This option supersedes
|
||||
<link linkend="opt.prof_leak"><mallctl>opt.prof_leak</mallctl></link>,
|
||||
meaning that if both are specified, this option takes precedence. When
|
||||
enabled, also enables <link linkend="opt.prof_leak"><mallctl>
|
||||
opt.prof_leak</mallctl></link>. Works only when combined with
|
||||
<link linkend="opt.prof_final"><mallctl>opt.prof_final</mallctl></link>,
|
||||
otherwise does nothing. This option is disabled by default.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.zero_realloc">
|
||||
<term>
|
||||
<mallctl>opt.zero_realloc</mallctl>
|
||||
|
@ -12,6 +12,7 @@ extern ssize_t opt_lg_prof_interval; /* lg(prof_interval). */
|
||||
extern bool opt_prof_gdump; /* High-water memory dumping. */
|
||||
extern bool opt_prof_final; /* Final profile dumping. */
|
||||
extern bool opt_prof_leak; /* Dump leak summary at exit. */
|
||||
extern bool opt_prof_leak_error; /* Exit with error code if memory leaked */
|
||||
extern bool opt_prof_accum; /* Report cumulative bytes. */
|
||||
extern bool opt_prof_log; /* Turn logging on at boot. */
|
||||
extern char opt_prof_prefix[
|
||||
|
@ -145,6 +145,7 @@ CTL_PROTO(opt_lg_prof_interval)
|
||||
CTL_PROTO(opt_prof_gdump)
|
||||
CTL_PROTO(opt_prof_final)
|
||||
CTL_PROTO(opt_prof_leak)
|
||||
CTL_PROTO(opt_prof_leak_error)
|
||||
CTL_PROTO(opt_prof_accum)
|
||||
CTL_PROTO(opt_prof_recent_alloc_max)
|
||||
CTL_PROTO(opt_prof_stats)
|
||||
@ -469,6 +470,7 @@ 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_leak_error"), CTL(opt_prof_leak_error)},
|
||||
{NAME("prof_accum"), CTL(opt_prof_accum)},
|
||||
{NAME("prof_recent_alloc_max"), CTL(opt_prof_recent_alloc_max)},
|
||||
{NAME("prof_stats"), CTL(opt_prof_stats)},
|
||||
@ -2201,6 +2203,7 @@ 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_CGEN(config_prof, opt_prof_leak_error, opt_prof_leak_error, bool)
|
||||
CTL_RO_NL_CGEN(config_prof, opt_prof_recent_alloc_max,
|
||||
opt_prof_recent_alloc_max, ssize_t)
|
||||
CTL_RO_NL_CGEN(config_prof, opt_prof_stats, opt_prof_stats, bool)
|
||||
|
@ -1578,6 +1578,26 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
|
||||
CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump")
|
||||
CONF_HANDLE_BOOL(opt_prof_final, "prof_final")
|
||||
CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak")
|
||||
if (CONF_MATCH("prof_leak_error")) {
|
||||
if (CONF_MATCH_VALUE("true")) {
|
||||
if (!opt_prof_final) {
|
||||
CONF_ERROR(
|
||||
"prof_leak_error is"
|
||||
" not allowed"
|
||||
" without"
|
||||
" prof_leak_final",
|
||||
k, klen, v, vlen);
|
||||
} else {
|
||||
opt_prof_leak = true;
|
||||
opt_prof_leak_error =
|
||||
true;
|
||||
}
|
||||
} else if (!CONF_MATCH_VALUE("false")) {
|
||||
CONF_ERROR("Invalid conf value",
|
||||
k, klen, v, vlen);
|
||||
}
|
||||
CONF_CONTINUE;
|
||||
}
|
||||
CONF_HANDLE_BOOL(opt_prof_log, "prof_log")
|
||||
CONF_HANDLE_SSIZE_T(opt_prof_recent_alloc_max,
|
||||
"prof_recent_alloc_max", -1, SSIZE_MAX)
|
||||
|
@ -31,6 +31,7 @@ ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
|
||||
bool opt_prof_gdump = false;
|
||||
bool opt_prof_final = false;
|
||||
bool opt_prof_leak = false;
|
||||
bool opt_prof_leak_error = false;
|
||||
bool opt_prof_accum = false;
|
||||
char opt_prof_prefix[PROF_DUMP_FILENAME_LEN];
|
||||
bool opt_prof_sys_thread_name = false;
|
||||
|
@ -1037,6 +1037,16 @@ prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx) {
|
||||
1) ? "s" : "", leak_ngctx, (leak_ngctx != 1) ? "s" : "");
|
||||
malloc_printf(
|
||||
"<jemalloc>: Run jeprof on dump output for leak detail\n");
|
||||
if (opt_prof_leak_error) {
|
||||
malloc_printf(
|
||||
"<jemalloc>: Exiting with error code because memory"
|
||||
" leaks were detected\n");
|
||||
/*
|
||||
* Use _exit() with underscore to avoid calling atexit()
|
||||
* and entering endless cycle.
|
||||
*/
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1530,6 +1530,7 @@ stats_general_print(emitter_t *emitter) {
|
||||
OPT_WRITE_BOOL("prof_gdump")
|
||||
OPT_WRITE_BOOL("prof_final")
|
||||
OPT_WRITE_BOOL("prof_leak")
|
||||
OPT_WRITE_BOOL("prof_leak_error")
|
||||
OPT_WRITE_BOOL("stats_print")
|
||||
OPT_WRITE_CHAR_P("stats_print_opts")
|
||||
OPT_WRITE_BOOL("stats_print")
|
||||
|
@ -320,6 +320,7 @@ TEST_BEGIN(test_mallctl_opt) {
|
||||
TEST_MALLCTL_OPT(bool, prof_gdump, prof);
|
||||
TEST_MALLCTL_OPT(bool, prof_final, prof);
|
||||
TEST_MALLCTL_OPT(bool, prof_leak, prof);
|
||||
TEST_MALLCTL_OPT(bool, prof_leak_error, prof);
|
||||
TEST_MALLCTL_OPT(ssize_t, prof_recent_alloc_max, prof);
|
||||
TEST_MALLCTL_OPT(bool, prof_stats, prof);
|
||||
TEST_MALLCTL_OPT(bool, prof_sys_thread_name, prof);
|
||||
|
Loading…
Reference in New Issue
Block a user