aboutsummaryrefslogtreecommitdiffstats
path: root/t/unit-tests
diff options
context:
space:
mode:
authorRené Scharfe <l.s.r@web.de>2024-12-28 10:48:00 +0100
committerJunio C Hamano <gitster@pobox.com>2024-12-28 08:00:44 -0800
commit2cca185e85171c462166839cfd6ee57c09573160 (patch)
treee768f5c93812fe2976a52319c0454d7c99b75248 /t/unit-tests
parent8db127d43f5b0eff254a851f9c966b7b85d91992 (diff)
downloadgit-2cca185e85171c462166839cfd6ee57c09573160.tar.gz
reftable: fix allocation count on realloc error
When realloc(3) fails, it returns NULL and keeps the original allocation intact. REFTABLE_ALLOC_GROW overwrites both the original pointer and the allocation count variable in that case, simultaneously leaking the original allocation and misrepresenting the number of storable items. parse_names() avoids the leak by keeping the original pointer if reallocation fails, but still increase the allocation count in such a case as if it succeeded. That's OK, because the error handling code just frees everything and doesn't look at names_cap anymore. reftable_buf_add() does the same, but here it is a problem as it leaves the reftable_buf in a broken state, with ->alloc being roughly twice as big as the actually allocated memory, allowing out-of-bounds writes in subsequent calls. Reimplement REFTABLE_ALLOC_GROW to avoid leaks, keep allocation counts in sync and still signal failures to callers while avoiding code duplication in callers. Make it an expression that evaluates to 0 if no reallocation is needed or it succeeded and 1 on failure while keeping the original pointer and allocation counter values. Adjust REFTABLE_ALLOC_GROW_OR_NULL to the new calling convention for REFTABLE_ALLOC_GROW, but keep its support for non-size_t alloc variables for now. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 't/unit-tests')
-rw-r--r--t/unit-tests/t-reftable-basics.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c
index 5bf79c9976..990dc1a244 100644
--- a/t/unit-tests/t-reftable-basics.c
+++ b/t/unit-tests/t-reftable-basics.c
@@ -146,6 +146,32 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
check_int(in, ==, out);
}
+ if_test ("REFTABLE_ALLOC_GROW works") {
+ int *arr = NULL, *old_arr;
+ size_t alloc = 0, old_alloc;
+
+ check(!REFTABLE_ALLOC_GROW(arr, 1, alloc));
+ check(arr != NULL);
+ check_uint(alloc, >=, 1);
+ arr[0] = 42;
+
+ old_alloc = alloc;
+ old_arr = arr;
+ reftable_set_alloc(malloc, realloc_stub, free);
+ check(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc));
+ check(arr == old_arr);
+ check_uint(alloc, ==, old_alloc);
+
+ old_alloc = alloc;
+ reftable_set_alloc(malloc, realloc, free);
+ check(!REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc));
+ check(arr != NULL);
+ check_uint(alloc, >, old_alloc);
+ arr[alloc - 1] = 42;
+
+ reftable_free(arr);
+ }
+
if_test ("REFTABLE_ALLOC_GROW_OR_NULL works") {
int *arr = NULL;
size_t alloc = 0, old_alloc;