Background threads: fix an indexing bug.

We have a buffer overrun that manifests in the case where arena indices higher
than the number of CPUs are accessed before arena indices lower than the number
of CPUs.  This fixes the bug and adds a test.
This commit is contained in:
David Goldblatt 2018-02-26 17:11:29 -08:00 committed by David Goldblatt
parent dd7e283b6f
commit 26b1c13982
3 changed files with 37 additions and 1 deletions

View File

@ -162,6 +162,7 @@ TESTS_UNIT := \
$(srcroot)test/unit/arena_reset.c \ $(srcroot)test/unit/arena_reset.c \
$(srcroot)test/unit/atomic.c \ $(srcroot)test/unit/atomic.c \
$(srcroot)test/unit/background_thread.c \ $(srcroot)test/unit/background_thread.c \
$(srcroot)test/unit/background_thread_enable.c \
$(srcroot)test/unit/base.c \ $(srcroot)test/unit/base.c \
$(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/bitmap.c \
$(srcroot)test/unit/ckh.c \ $(srcroot)test/unit/ckh.c \

View File

@ -600,7 +600,8 @@ background_threads_enable(tsd_t *tsd) {
arena_get(tsd_tsdn(tsd), i, false) == NULL) { arena_get(tsd_tsdn(tsd), i, false) == NULL) {
continue; continue;
} }
background_thread_info_t *info = &background_thread_info[i]; background_thread_info_t *info = &background_thread_info[
i % ncpus];
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
assert(info->state == background_thread_stopped); assert(info->state == background_thread_stopped);
background_thread_init(tsd, info); background_thread_init(tsd, info);

View File

@ -0,0 +1,34 @@
#include "test/jemalloc_test.h"
const char *malloc_conf = "background_thread:false,narenas:1";
TEST_BEGIN(test_deferred) {
test_skip_if(!have_background_thread);
unsigned id;
size_t sz_u = sizeof(unsigned);
/*
* 10 here is somewhat arbitrary, except insofar as we want to ensure
* that the number of background threads is smaller than the number of
* arenas. I'll ragequit long before we have to spin up 10 threads per
* cpu to handle background purging, so this is a conservative
* approximation.
*/
for (unsigned i = 0; i < 10 * ncpus; i++) {
assert_d_eq(mallctl("arenas.create", &id, &sz_u, NULL, 0), 0,
"Failed to create arena");
}
bool enable = true;
size_t sz_b = sizeof(bool);
assert_d_eq(mallctl("background_thread", NULL, NULL, &enable, sz_b), 0,
"Failed to enable background threads");
}
TEST_END
int
main(void) {
return test_no_reentrancy(
test_deferred);
}