summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2024-10-30 14:57:23 -0400
committerTavian Barnes <tavianator@tavianator.com>2024-11-02 11:25:10 -0400
commitd09b784e395554cb67ec91e70544a052fe60a276 (patch)
tree7ac772d169160cd0d274203e0fd2b09e74023427
parent1466fb2400af367db9d0cb1041020278a871a4f3 (diff)
downloadbfs-d09b784e395554cb67ec91e70544a052fe60a276.tar.xz
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.
-rw-r--r--src/alloc.c6
-rw-r--r--src/sanity.h14
-rw-r--r--tests/alloc.c44
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 <sanitizer/asan_interface.h>
@@ -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__
@@ -65,11 +70,6 @@
#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.
*/
#if __SANITIZE_MEMORY__
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 <stdlib.h>
#include <stdint.h>
+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);
}