From d09b784e395554cb67ec91e70544a052fe60a276 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 30 Oct 2024 14:57:23 -0400 Subject: sanity: Don't mark memory uninit in sanitize_{alloc,free}() We might want to change the size of an allocated region without changing which bytes are initialized. --- src/alloc.c | 6 ++++-- src/sanity.h | 14 +++++++------- tests/alloc.c | 44 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 79e4ce7..ef9f6ab 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -228,6 +228,7 @@ void arena_free(struct arena *arena, void *ptr) { union chunk *chunk = ptr; chunk_set_next(arena, chunk, arena->chunks); arena->chunks = chunk; + sanitize_uninit(chunk, arena->size); sanitize_free(chunk, arena->size); } @@ -334,15 +335,16 @@ void *varena_realloc(struct varena *varena, void *ptr, size_t old_count, size_t } size_t old_size = old_arena->size; - sanitize_alloc((char *)ptr + old_exact_size, old_size - old_exact_size); + sanitize_alloc(ptr, old_size); size_t new_size = new_arena->size; size_t min_size = new_size < old_size ? new_size : old_size; memcpy(ret, ptr, min_size); arena_free(old_arena, ptr); - sanitize_free((char *)ret + new_exact_size, new_size - new_exact_size); + sanitize_free(ret, new_size); + sanitize_alloc(ret, new_exact_size); return ret; } diff --git a/src/sanity.h b/src/sanity.h index 0b770cf..3f6020b 100644 --- a/src/sanity.h +++ b/src/sanity.h @@ -20,6 +20,11 @@ #define SANITIZE_CALL__(macro, ptr, size, ...) \ macro(ptr, size) +/** + * Squelch unused variable warnings when not sanitizing. + */ +#define sanitize_ignore(ptr, size) ((void)(ptr), (void)(size)) + #if __SANITIZE_ADDRESS__ # include @@ -38,8 +43,8 @@ #define sanitize_free(...) SANITIZE_CALL(__asan_poison_memory_region, __VA_ARGS__) #else -# define sanitize_alloc sanitize_uninit -# define sanitize_free sanitize_uninit +# define sanitize_alloc(...) SANITIZE_CALL(sanitize_ignore, __VA_ARGS__) +# define sanitize_free(...) SANITIZE_CALL(sanitize_ignore, __VA_ARGS__) #endif #if __SANITIZE_MEMORY__ @@ -64,11 +69,6 @@ # define sanitize_uninit(...) SANITIZE_CALL(sanitize_ignore, __VA_ARGS__) #endif -/** - * Squelch unused variable warnings when not sanitizing. - */ -#define sanitize_ignore(ptr, size) ((void)(ptr), (void)(size)) - /** * Initialize a variable, unless sanitizers would detect uninitialized uses. */ diff --git a/tests/alloc.c b/tests/alloc.c index 5fc934b..4aae515 100644 --- a/tests/alloc.c +++ b/tests/alloc.c @@ -10,6 +10,27 @@ #include #include +struct flexible { + alignas(64) int foo[8]; + int bar[]; +}; + +/** Check varena_realloc() poisoning for a size combination. */ +static struct flexible *check_varena_realloc(struct varena *varena, struct flexible *flexy, size_t old_count, size_t new_count) { + flexy = varena_realloc(varena, flexy, old_count, new_count); + bfs_everify(flexy); + + for (size_t i = 0; i < new_count; ++i) { + if (i < old_count) { + bfs_check(flexy->bar[i] == (int)i); + } else { + flexy->bar[i] = i; + } + } + + return flexy; +} + void check_alloc(void) { // Check aligned allocation void *ptr; @@ -20,21 +41,14 @@ void check_alloc(void) { free(ptr); // Check sizeof_flex() - struct flexible { - alignas(64) int foo[8]; - int bar[]; - }; bfs_check(sizeof_flex(struct flexible, bar, 0) >= sizeof(struct flexible)); bfs_check(sizeof_flex(struct flexible, bar, 16) % alignof(struct flexible) == 0); - size_t too_many = SIZE_MAX / sizeof(int) + 1; + // volatile to suppress -Walloc-size-larger-than + volatile size_t too_many = SIZE_MAX / sizeof(int) + 1; bfs_check(sizeof_flex(struct flexible, bar, too_many) == align_floor(alignof(struct flexible), SIZE_MAX)); // Make sure we detect allocation size overflows -#if __GNUC__ && !__clang__ -# pragma GCC diagnostic ignored "-Walloc-size-larger-than=" -#endif - bfs_check(ALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW); bfs_check(ZALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW); bfs_check(ALLOC_FLEX(struct flexible, bar, too_many) == NULL && errno == EOVERFLOW); @@ -45,10 +59,20 @@ void check_alloc(void) { VARENA_INIT(&varena, struct flexible, bar); for (size_t i = 0; i < 256; ++i) { - bfs_verify(varena_alloc(&varena, i)); + bfs_everify(varena_alloc(&varena, i)); struct arena *arena = &varena.arenas[varena.narenas - 1]; bfs_check(arena->size >= sizeof_flex(struct flexible, bar, i)); } + // Check varena_realloc() (un)poisoning + struct flexible *flexy = varena_alloc(&varena, 160); + bfs_everify(flexy); + + flexy = check_varena_realloc(&varena, flexy, 0, 160); + flexy = check_varena_realloc(&varena, flexy, 160, 192); + flexy = check_varena_realloc(&varena, flexy, 192, 160); + flexy = check_varena_realloc(&varena, flexy, 160, 320); + flexy = check_varena_realloc(&varena, flexy, 320, 96); + varena_destroy(&varena); } -- cgit v1.2.3