Add mallctl to set and get ncached_max of each cache_bin.
1. `thread_tcache_ncached_max_read_sizeclass` allows users to get the ncached_max of the bin with the input sizeclass, passed in through oldp (will be upper casted if not an exact bin size is given). 2. `thread_tcache_ncached_max_write` takes in a char array representing the settings for bins in the tcache.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
#include "test/san.h"
|
||||
|
||||
const char *malloc_conf = TEST_SAN_UAF_ALIGN_DISABLE;
|
||||
extern void tcache_bin_info_compute(
|
||||
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]);
|
||||
|
||||
enum {
|
||||
alloc_option_start = 0,
|
||||
@@ -260,7 +262,7 @@ tcache_check(void *arg) {
|
||||
expect_zu_eq(old_tcache_max, opt_tcache_max,
|
||||
"Unexpected default value for tcache_max");
|
||||
tcache_nbins = tcache_nbins_get(tcache_slow);
|
||||
expect_zu_eq(tcache_nbins, (size_t)global_do_not_change_nbins,
|
||||
expect_zu_eq(tcache_nbins, (size_t)global_do_not_change_tcache_nbins,
|
||||
"Unexpected default value for tcache_nbins");
|
||||
validate_tcache_stack(tcache);
|
||||
|
||||
@@ -364,10 +366,238 @@ 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_thread_tcache_max,
|
||||
test_ncached_max);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user