diff --git a/Makefile.in b/Makefile.in index 594ea4f2..df244adb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -242,6 +242,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/mq.c \ $(srcroot)test/unit/mtx.c \ $(srcroot)test/unit/nstime.c \ + $(srcroot)test/unit/ncached_max.c \ $(srcroot)test/unit/oversize_threshold.c \ $(srcroot)test/unit/pa.c \ $(srcroot)test/unit/pack.c \ diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index aa7ca00f..973dbfe9 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -35,6 +35,11 @@ extern unsigned global_do_not_change_tcache_nbins; */ extern size_t global_do_not_change_tcache_maxclass; +/* Default bin info for each bin. */ +extern cache_bin_info_t opt_tcache_ncached_max[TCACHE_NBINS_MAX]; +/* Records whether a bin's info is specified by malloc_conf. */ +extern bool opt_tcache_ncached_max_set[TCACHE_NBINS_MAX]; + /* * Explicit tcaches, managed via the tcache.{create,flush,destroy} mallctls and * usable via the MALLOCX_TCACHE() flag. The automatic per thread tcaches are @@ -55,6 +60,9 @@ void tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin, szind_t binind, unsigned rem); void tcache_bin_flush_stashed(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin, szind_t binind, bool is_small); +bool tcache_bin_info_settings_parse(const char *bin_settings_segment_cur, + size_t len_left, cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX], + bool bin_info_is_set[TCACHE_NBINS_MAX]); bool tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len); bool tcache_bin_ncached_max_read(tsd_t *tsd, size_t bin_size, cache_bin_sz_t *ncached_max); diff --git a/src/jemalloc.c b/src/jemalloc.c index 9c4e578e..c77f2ef2 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1322,6 +1322,18 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS], } while (vlen_left > 0); CONF_CONTINUE; } + if (CONF_MATCH("tcache_ncached_max")) { + bool err = tcache_bin_info_settings_parse( + v, vlen, opt_tcache_ncached_max, + opt_tcache_ncached_max_set); + if (err) { + CONF_ERROR("Invalid settings for " + "tcache_ncached_max", k, klen, v, + vlen); + break; + } + CONF_CONTINUE; + } CONF_HANDLE_INT64_T(opt_mutex_max_spin, "mutex_max_spin", -1, INT64_MAX, CONF_CHECK_MIN, CONF_DONT_CHECK_MAX, false); diff --git a/src/tcache.c b/src/tcache.c index 3fc2cae2..a8eaf296 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -71,6 +71,15 @@ unsigned global_do_not_change_tcache_nbins; */ size_t global_do_not_change_tcache_maxclass; +/* Default bin info for each bin. Will be initialized when thread starts. */ +cache_bin_info_t opt_tcache_ncached_max[TCACHE_NBINS_MAX] = {{0}}; +/* + * Marks whether a bin's info is set already. This is used in + * tcache_bin_info_compute to avoid overwriting ncached_max specified by + * malloc_conf. + */ +bool opt_tcache_ncached_max_set[TCACHE_NBINS_MAX] = {0}; + tcaches_t *tcaches; /* Index of first element within tcaches that has never been used. */ @@ -800,7 +809,9 @@ tcache_bin_info_compute(cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) { * than tcache_nbins, no items will be cached. */ for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { - unsigned ncached_max = tcache_ncached_max_compute(i); + unsigned ncached_max = opt_tcache_ncached_max_set[i] ? + opt_tcache_ncached_max[i].ncached_max: + tcache_ncached_max_compute(i); assert(ncached_max <= CACHE_BIN_NCACHED_MAX); cache_bin_info_init(&tcache_bin_info[i], ncached_max); } @@ -984,17 +995,9 @@ thread_tcache_max_set(tsd_t *tsd, size_t tcache_max) { assert(tcache_nbins_get(tcache_slow) == sz_size2index(tcache_max) + 1); } -bool -tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len) { - assert(tcache_available(tsd)); - tcache_t *tcache = tsd_tcachep_get(tsd); - assert(tcache != NULL); - cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]; - tcache_bin_settings_backup(tcache, tcache_bin_info); - const char *bin_settings_segment_cur = settings; - size_t len_left = len; - assert(len_left != 0); - +bool tcache_bin_info_settings_parse(const char *bin_settings_segment_cur, + size_t len_left, cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX], + bool bin_info_is_set[TCACHE_NBINS_MAX]) { do { size_t size_start, size_end; size_t ncached_max; @@ -1019,9 +1022,29 @@ tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len) { for (szind_t i = bin_start; i <= bin_end; i++) { cache_bin_info_init(&tcache_bin_info[i], (cache_bin_sz_t)ncached_max); + if (bin_info_is_set != NULL) { + bin_info_is_set[i] = true; + } } } while (len_left > 0); + return false; +} + +bool +tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len) { + assert(tcache_available(tsd)); + assert(len != 0); + tcache_t *tcache = tsd_tcachep_get(tsd); + assert(tcache != NULL); + cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]; + tcache_bin_settings_backup(tcache, tcache_bin_info); + + if(tcache_bin_info_settings_parse(settings, len, tcache_bin_info, + NULL)) { + return true; + } + arena_t *assigned_arena = tcache->tcache_slow->arena; tcache_cleanup(tsd); tsd_tcache_data_init_with_bin_settings(tsd, assigned_arena, diff --git a/test/unit/ncached_max.c b/test/unit/ncached_max.c new file mode 100644 index 00000000..da35d7c9 --- /dev/null +++ b/test/unit/ncached_max.c @@ -0,0 +1,264 @@ +#include "test/jemalloc_test.h" +#include "test/san.h" + +const char *malloc_conf = +"tcache_ncached_max:256-1024:1001|2048-2048:0,tcache_max:4096"; +extern void tcache_bin_info_compute( + cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]); + +static void +check_bins_info(cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) { + size_t mib_get[4], mib_get_len; + mib_get_len = sizeof(mib_get) / sizeof(size_t); + const char *get_name = "thread.tcache.ncached_max.read_sizeclass"; + size_t ncached_max; + size_t sz = sizeof(size_t); + expect_d_eq(mallctlnametomib(get_name, mib_get, &mib_get_len), 0, + "Unexpected mallctlnametomib() failure"); + + for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { + size_t bin_size = sz_index2size(i); + expect_d_eq(mallctlbymib(mib_get, mib_get_len, + (void *)&ncached_max, &sz, + (void *)&bin_size, sizeof(size_t)), 0, + "Unexpected mallctlbymib() failure"); + expect_zu_eq(ncached_max, tcache_bin_info[i].ncached_max, + "Unexpected ncached_max for bin %d", i); + /* Check ncached_max returned under a non-bin size. */ + bin_size--; + size_t temp_ncached_max = 0; + expect_d_eq(mallctlbymib(mib_get, mib_get_len, + (void *)&temp_ncached_max, &sz, + (void *)&bin_size, sizeof(size_t)), 0, + "Unexpected mallctlbymib() failure"); + expect_zu_eq(temp_ncached_max, ncached_max, + "Unexpected ncached_max for inaccurate bin size."); + } +} + +static void * +ncached_max_check(void* args) { + cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]; + cache_bin_info_t tcache_bin_info_backup[TCACHE_NBINS_MAX]; + tsd_t *tsd = tsd_fetch(); + tcache_t *tcache = tsd_tcachep_get(tsd); + assert(tcache != NULL); + tcache_slow_t *tcache_slow = tcache->tcache_slow; + + + tcache_bin_info_compute(tcache_bin_info); + memcpy(tcache_bin_info_backup, tcache_bin_info, + sizeof(tcache_bin_info)); + /* Check ncached_max set by malloc_conf. */ + for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { + bool first_range = (i >= sz_size2index(256) && + i <= sz_size2index(1024)); + bool second_range = (i == sz_size2index(2048)); + cache_bin_sz_t target_ncached_max = 0; + if (first_range || second_range) { + target_ncached_max = first_range ? 1001: 0; + expect_true(opt_tcache_ncached_max_set[i], + "Unexpected state for bin %u", i); + expect_zu_eq(target_ncached_max, + tcache_bin_info[i].ncached_max, + "Unexpected generated ncached_max for bin %u", i); + } else { + expect_false(opt_tcache_ncached_max_set[i], + "Unexpected state for bin %u", i); + } + expect_zu_eq(target_ncached_max, + opt_tcache_ncached_max[i].ncached_max, + "Unexpected pre-set ncached_max for bin %u", i); + } + unsigned nbins = tcache_nbins_get(tcache_slow); + for (szind_t i = nbins; i < TCACHE_NBINS_MAX; i++) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + /* Check the initial bin settings. */ + check_bins_info(tcache_bin_info); + + size_t mib_set[4], mib_set_len; + mib_set_len = sizeof(mib_set) / sizeof(size_t); + const char *set_name = "thread.tcache.ncached_max.write"; + expect_d_eq(mallctlnametomib(set_name, mib_set, &mib_set_len), 0, + "Unexpected mallctlnametomib() failure"); + + /* Test the ncached_max set with tcache on. */ + char inputs[100] = "8-128:1|160-160:11|170-320:22|224-8388609:0"; + char *inputp = inputs; + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), 0, + "Unexpected mallctlbymib() failure"); + for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { + if (i >= sz_size2index(8) &&i <= sz_size2index(128)) { + cache_bin_info_init(&tcache_bin_info[i], 1); + } + if (i == sz_size2index(160)) { + cache_bin_info_init(&tcache_bin_info[i], 11); + } + if (i >= sz_size2index(170) && i <= sz_size2index(320)) { + cache_bin_info_init(&tcache_bin_info[i], 22); + } + if (i >= sz_size2index(224)) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + if (i >= nbins) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + } + check_bins_info(tcache_bin_info); + + /* + * Close the tcache and set ncached_max of some bins. It will be + * set properly but thread.tcache.ncached_max.read still returns 0 + * since the bin is not available yet. After enabling the tcache, + * the new setting will not be carried on. Instead, the default + * settings will be applied. + */ + bool e0 = false, e1; + size_t bool_sz = sizeof(bool); + expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz, + (void *)&e0, bool_sz), 0, "Unexpected mallctl() error"); + expect_true(e1, "Unexpected previous tcache state"); + strcpy(inputs, "0-112:8"); + /* Setting returns ENOENT when the tcache is disabled. */ + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), ENOENT, + "Unexpected mallctlbymib() failure"); + /* All ncached_max should return 0 once tcache is disabled. */ + for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + check_bins_info(tcache_bin_info); + + e0 = true; + expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz, + (void *)&e0, bool_sz), 0, "Unexpected mallctl() error"); + expect_false(e1, "Unexpected previous tcache state"); + memcpy(tcache_bin_info, tcache_bin_info_backup, + sizeof(tcache_bin_info_backup)); + for (szind_t i = tcache_nbins_get(tcache_slow); i < TCACHE_NBINS_MAX; + i++) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + check_bins_info(tcache_bin_info); + + /* + * Set ncached_max of bins not enabled yet. Then, enable them by + * resetting tcache_max. The ncached_max changes should stay. + */ + size_t tcache_max = 1024; + assert_d_eq(mallctl("thread.tcache.max", + NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0, + "Unexpected.mallctl().failure"); + for (szind_t i = sz_size2index(1024) + 1; i < TCACHE_NBINS_MAX; i++) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + strcpy(inputs, "2048-6144:123"); + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), 0, + "Unexpected mallctlbymib() failure"); + check_bins_info(tcache_bin_info); + + tcache_max = 6144; + assert_d_eq(mallctl("thread.tcache.max", + NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0, + "Unexpected.mallctl().failure"); + memcpy(tcache_bin_info, tcache_bin_info_backup, + sizeof(tcache_bin_info_backup)); + for (szind_t i = sz_size2index(2048); i < TCACHE_NBINS_MAX; i++) { + if (i <= sz_size2index(6144)) { + cache_bin_info_init(&tcache_bin_info[i], 123); + } else if (i > sz_size2index(6144)) { + cache_bin_info_init(&tcache_bin_info[i], 0); + } + } + check_bins_info(tcache_bin_info); + + /* Test an empty input, it should do nothing. */ + strcpy(inputs, ""); + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), 0, + "Unexpected mallctlbymib() failure"); + check_bins_info(tcache_bin_info); + + /* Test a half-done string, it should return EINVAL and do nothing. */ + strcpy(inputs, "4-1024:7|256-1024"); + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), EINVAL, + "Unexpected mallctlbymib() failure"); + check_bins_info(tcache_bin_info); + + /* + * Test an invalid string with start size larger than end size. It + * should return success but do nothing. + */ + strcpy(inputs, "1024-256:7"); + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), 0, + "Unexpected mallctlbymib() failure"); + check_bins_info(tcache_bin_info); + + /* + * Test a string exceeding the length limit, it should return EINVAL + * and do nothing. + */ + char *long_inputs = (char *)malloc(10000 * sizeof(char)); + expect_true(long_inputs != NULL, "Unexpected allocation failure."); + for (int i = 0; i < 200; i++) { + memcpy(long_inputs + i * 9, "4-1024:3|", 9); + } + memcpy(long_inputs + 200 * 9, "4-1024:3", 8); + long_inputs[200 * 9 + 8] = '\0'; + inputp = long_inputs; + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), EINVAL, + "Unexpected mallctlbymib() failure"); + check_bins_info(tcache_bin_info); + free(long_inputs); + + /* + * Test a string with invalid characters, it should return EINVAL + * and do nothing. + */ + strcpy(inputs, "k8-1024:77p"); + inputp = inputs; + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), EINVAL, + "Unexpected mallctlbymib() failure"); + check_bins_info(tcache_bin_info); + + /* Test large ncached_max, it should return success but capped. */ + strcpy(inputs, "1024-1024:65540"); + expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, + (void *)&inputp, sizeof(char *)), 0, + "Unexpected mallctlbymib() failure"); + cache_bin_info_init(&tcache_bin_info[sz_size2index(1024)], + CACHE_BIN_NCACHED_MAX); + check_bins_info(tcache_bin_info); + + return NULL; +} + +TEST_BEGIN(test_ncached_max) { + test_skip_if(!config_stats); + test_skip_if(!opt_tcache); + test_skip_if(san_uaf_detection_enabled()); + /* TODO: change nthreads to 8 to reduce CI loads. */ + unsigned nthreads = 108; + VARIABLE_ARRAY(thd_t, threads, nthreads); + for (unsigned i = 0; i < nthreads; i++) { + thd_create(&threads[i], ncached_max_check, NULL); + } + for (unsigned i = 0; i < nthreads; i++) { + thd_join(threads[i], NULL); + } +} +TEST_END + +int +main(void) { + return test( + test_ncached_max); +} + diff --git a/test/unit/tcache_max.c b/test/unit/tcache_max.c index 5793cb6b..32eacadf 100644 --- a/test/unit/tcache_max.c +++ b/test/unit/tcache_max.c @@ -366,238 +366,10 @@ TEST_BEGIN(test_thread_tcache_max) { } TEST_END -static void -check_bins_info(cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) { - size_t mib_get[4], mib_get_len; - mib_get_len = sizeof(mib_get) / sizeof(size_t); - const char *get_name = "thread.tcache.ncached_max.read_sizeclass"; - size_t ncached_max; - size_t sz = sizeof(size_t); - expect_d_eq(mallctlnametomib(get_name, mib_get, &mib_get_len), 0, - "Unexpected mallctlnametomib() failure"); - - for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { - size_t bin_size = sz_index2size(i); - expect_d_eq(mallctlbymib(mib_get, mib_get_len, - (void *)&ncached_max, &sz, - (void *)&bin_size, sizeof(size_t)), 0, - "Unexpected mallctlbymib() failure"); - expect_zu_eq(ncached_max, tcache_bin_info[i].ncached_max, - "Unexpected ncached_max for bin %d", i); - /* Check ncached_max returned under a non-bin size. */ - bin_size--; - size_t temp_ncached_max = 0; - expect_d_eq(mallctlbymib(mib_get, mib_get_len, - (void *)&temp_ncached_max, &sz, - (void *)&bin_size, sizeof(size_t)), 0, - "Unexpected mallctlbymib() failure"); - expect_zu_eq(temp_ncached_max, ncached_max, - "Unexpected ncached_max for inaccurate bin size."); - } -} - -static void * -ncached_max_check(void* args) { - cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]; - cache_bin_info_t tcache_bin_info_backup[TCACHE_NBINS_MAX]; - tsd_t *tsd = tsd_fetch(); - tcache_t *tcache = tsd_tcachep_get(tsd); - assert(tcache != NULL); - tcache_slow_t *tcache_slow = tcache->tcache_slow; - - /* Check the initial bin settings. */ - tcache_bin_info_compute(tcache_bin_info); - memcpy(tcache_bin_info_backup, tcache_bin_info, - sizeof(tcache_bin_info)); - unsigned nbins = tcache_nbins_get(tcache_slow); - for (szind_t i = nbins; i < TCACHE_NBINS_MAX; i++) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - check_bins_info(tcache_bin_info); - - size_t mib_set[4], mib_set_len; - mib_set_len = sizeof(mib_set) / sizeof(size_t); - const char *set_name = "thread.tcache.ncached_max.write"; - expect_d_eq(mallctlnametomib(set_name, mib_set, &mib_set_len), 0, - "Unexpected mallctlnametomib() failure"); - - /* Test the ncached_max set with tcache on. */ - char inputs[100] = "8-128:1|160-160:11|170-320:22|224-8388609:0"; - char *inputp = inputs; - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), 0, - "Unexpected mallctlbymib() failure"); - for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { - if (i >= sz_size2index(8) &&i <= sz_size2index(128)) { - cache_bin_info_init(&tcache_bin_info[i], 1); - } - if (i == sz_size2index(160)) { - cache_bin_info_init(&tcache_bin_info[i], 11); - } - if (i >= sz_size2index(170) && i <= sz_size2index(320)) { - cache_bin_info_init(&tcache_bin_info[i], 22); - } - if (i >= sz_size2index(224)) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - if (i >= nbins) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - } - check_bins_info(tcache_bin_info); - - /* - * Close the tcache and set ncached_max of some bins. It will be - * set properly but thread.tcache.ncached_max.read still returns 0 - * since the bin is not available yet. After enabling the tcache, - * the new setting will not be carried on. Instead, the default - * settings will be applied. - */ - bool e0 = false, e1; - size_t bool_sz = sizeof(bool); - expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz, - (void *)&e0, bool_sz), 0, "Unexpected mallctl() error"); - expect_true(e1, "Unexpected previous tcache state"); - strcpy(inputs, "0-112:8"); - /* Setting returns ENOENT when the tcache is disabled. */ - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), ENOENT, - "Unexpected mallctlbymib() failure"); - /* All ncached_max should return 0 once tcache is disabled. */ - for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - check_bins_info(tcache_bin_info); - - e0 = true; - expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz, - (void *)&e0, bool_sz), 0, "Unexpected mallctl() error"); - expect_false(e1, "Unexpected previous tcache state"); - memcpy(tcache_bin_info, tcache_bin_info_backup, - sizeof(tcache_bin_info_backup)); - for (szind_t i = tcache_nbins_get(tcache_slow); i < TCACHE_NBINS_MAX; - i++) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - check_bins_info(tcache_bin_info); - - /* - * Set ncached_max of bins not enabled yet. Then, enable them by - * resetting tcache_max. The ncached_max changes should stay. - */ - size_t tcache_max = 1024; - assert_d_eq(mallctl("thread.tcache.max", - NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0, - "Unexpected.mallctl().failure"); - for (szind_t i = sz_size2index(1024) + 1; i < TCACHE_NBINS_MAX; i++) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - strcpy(inputs, "2048-6144:123"); - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), 0, - "Unexpected mallctlbymib() failure"); - check_bins_info(tcache_bin_info); - - tcache_max = 6144; - assert_d_eq(mallctl("thread.tcache.max", - NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0, - "Unexpected.mallctl().failure"); - memcpy(tcache_bin_info, tcache_bin_info_backup, - sizeof(tcache_bin_info_backup)); - for (szind_t i = sz_size2index(2048); i < TCACHE_NBINS_MAX; i++) { - if (i <= sz_size2index(6144)) { - cache_bin_info_init(&tcache_bin_info[i], 123); - } else if (i > sz_size2index(6144)) { - cache_bin_info_init(&tcache_bin_info[i], 0); - } - } - check_bins_info(tcache_bin_info); - - /* Test an empty input, it should do nothing. */ - strcpy(inputs, ""); - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), 0, - "Unexpected mallctlbymib() failure"); - check_bins_info(tcache_bin_info); - - /* Test a half-done string, it should return EINVAL and do nothing. */ - strcpy(inputs, "4-1024:7|256-1024"); - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), EINVAL, - "Unexpected mallctlbymib() failure"); - check_bins_info(tcache_bin_info); - - /* - * Test an invalid string with start size larger than end size. It - * should return success but do nothing. - */ - strcpy(inputs, "1024-256:7"); - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), 0, - "Unexpected mallctlbymib() failure"); - check_bins_info(tcache_bin_info); - - /* - * Test a string exceeding the length limit, it should return EINVAL - * and do nothing. - */ - char *long_inputs = (char *)malloc(10000 * sizeof(char)); - expect_true(long_inputs != NULL, "Unexpected allocation failure."); - for (int i = 0; i < 200; i++) { - memcpy(long_inputs + i * 9, "4-1024:3|", 9); - } - memcpy(long_inputs + 200 * 9, "4-1024:3", 8); - long_inputs[200 * 9 + 8] = '\0'; - inputp = long_inputs; - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), EINVAL, - "Unexpected mallctlbymib() failure"); - check_bins_info(tcache_bin_info); - free(long_inputs); - - /* - * Test a string with invalid characters, it should return EINVAL - * and do nothing. - */ - strcpy(inputs, "k8-1024:77p"); - inputp = inputs; - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), EINVAL, - "Unexpected mallctlbymib() failure"); - check_bins_info(tcache_bin_info); - - /* Test large ncached_max, it should return success but capped. */ - strcpy(inputs, "1024-1024:65540"); - expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL, - (void *)&inputp, sizeof(char *)), 0, - "Unexpected mallctlbymib() failure"); - cache_bin_info_init(&tcache_bin_info[sz_size2index(1024)], - CACHE_BIN_NCACHED_MAX); - check_bins_info(tcache_bin_info); - - return NULL; -} - -TEST_BEGIN(test_ncached_max) { - test_skip_if(!config_stats); - test_skip_if(!opt_tcache); - test_skip_if(san_uaf_detection_enabled()); - unsigned nthreads = 8; - VARIABLE_ARRAY(thd_t, threads, nthreads); - for (unsigned i = 0; i < nthreads; i++) { - thd_create(&threads[i], ncached_max_check, NULL); - } - for (unsigned i = 0; i < nthreads; i++) { - thd_join(threads[i], NULL); - } -} -TEST_END - int main(void) { return test( test_tcache_max, - test_thread_tcache_max, - test_ncached_max); + test_thread_tcache_max); }