diff --git a/include/jemalloc/internal/prof_inlines_a.h b/include/jemalloc/internal/prof_inlines_a.h index 471d9853..6716d2f4 100644 --- a/include/jemalloc/internal/prof_inlines_a.h +++ b/include/jemalloc/internal/prof_inlines_a.h @@ -71,8 +71,19 @@ prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, #endif } +JEMALLOC_ALWAYS_INLINE void +prof_active_assert() { + cassert(config_prof); + /* + * If opt_prof is off, then prof_active must always be off, regardless + * of whether prof_active_mtx is in effect or not. + */ + assert(opt_prof || !prof_active); +} + JEMALLOC_ALWAYS_INLINE bool prof_active_get_unlocked(void) { + prof_active_assert(); /* * Even if opt_prof is true, sampling can be temporarily disabled by * setting prof_active to false. No locking is used when reading diff --git a/src/ctl.c b/src/ctl.c index 6bd534a7..fd05c08b 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -2662,7 +2662,8 @@ prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, bool oldval; if (!config_prof) { - return ENOENT; + ret = ENOENT; + goto label_return; } if (newp != NULL) { @@ -2670,7 +2671,12 @@ prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = EINVAL; goto label_return; } - oldval = prof_active_set(tsd_tsdn(tsd), *(bool *)newp); + bool val = *(bool *)newp; + if (!opt_prof && val) { + ret = ENOENT; + goto label_return; + } + oldval = prof_active_set(tsd_tsdn(tsd), val); } else { oldval = prof_active_get(tsd_tsdn(tsd)); } diff --git a/src/prof.c b/src/prof.c index 9ea4eda4..e00151d3 100644 --- a/src/prof.c +++ b/src/prof.c @@ -788,6 +788,7 @@ bool prof_active_get(tsdn_t *tsdn) { bool prof_active_current; + prof_active_assert(); malloc_mutex_lock(tsdn, &prof_active_mtx); prof_active_current = prof_active; malloc_mutex_unlock(tsdn, &prof_active_mtx); @@ -798,10 +799,12 @@ bool prof_active_set(tsdn_t *tsdn, bool active) { bool prof_active_old; + prof_active_assert(); malloc_mutex_lock(tsdn, &prof_active_mtx); prof_active_old = prof_active; prof_active = active; malloc_mutex_unlock(tsdn, &prof_active_mtx); + prof_active_assert(); return prof_active_old; } diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 3a75ac04..0e88f314 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -762,6 +762,32 @@ TEST_BEGIN(test_arenas_lookup) { } TEST_END +TEST_BEGIN(test_prof_active) { + /* + * If config_prof is off, then the test for prof_active in + * test_mallctl_opt was already enough. + */ + test_skip_if(!config_prof); + + bool active, old; + size_t len = sizeof(bool); + + active = true; + assert_d_eq(mallctl("prof.active", NULL, NULL, &active, len), ENOENT, + "Setting prof_active to true should fail when opt_prof is off"); + old = true; + assert_d_eq(mallctl("prof.active", &old, &len, &active, len), ENOENT, + "Setting prof_active to true should fail when opt_prof is off"); + assert_true(old, "old valud should not be touched when mallctl fails"); + active = false; + assert_d_eq(mallctl("prof.active", NULL, NULL, &active, len), 0, + "Setting prof_active to false should succeed when opt_prof is off"); + assert_d_eq(mallctl("prof.active", &old, &len, &active, len), 0, + "Setting prof_active to false should succeed when opt_prof is off"); + assert_false(old, "prof_active should be false when opt_prof is off"); +} +TEST_END + TEST_BEGIN(test_stats_arenas) { #define TEST_STATS_ARENAS(t, name) do { \ t name; \ @@ -882,6 +908,7 @@ main(void) { test_arenas_lextent_constants, test_arenas_create, test_arenas_lookup, + test_prof_active, test_stats_arenas, test_hooks, test_hooks_exhaustion);