Changes since v1: - added unit tests - explicitly set pointer to NULL on REFTABLE_ALLOC_GROW_OR_NULL failure in patch 2; omission found by unit test reftable: avoid leaks on realloc error reftable: fix allocation count on realloc error reftable: handle realloc error in parse_names() t-reftable-merged: handle realloc errors reftable/basics.c | 14 +++----- reftable/basics.h | 41 ++++++++++++++++++----- reftable/block.c | 10 +++--- reftable/pq.c | 2 +- reftable/record.c | 12 +++---- reftable/stack.c | 8 +++-- reftable/writer.c | 5 +-- t/unit-tests/t-reftable-basics.c | 56 ++++++++++++++++++++++++++++++++ t/unit-tests/t-reftable-merged.c | 4 +-- 9 files changed, 116 insertions(+), 36 deletions(-) Range-diff against v1: 1: b41547720d ! 1: b3cad92038 reftable: avoid leaks on realloc error @@ reftable/writer.c: static int writer_flush_nonempty_block(struct reftable_writer if (!w->index) return REFTABLE_OUT_OF_MEMORY_ERROR; + + ## t/unit-tests/t-reftable-basics.c ## +@@ t/unit-tests/t-reftable-basics.c: static int integer_needle_lesseq(size_t i, void *_args) + return args->needle <= args->haystack[i]; + } + ++static void *realloc_stub(void *p UNUSED, size_t size UNUSED) ++{ ++ return NULL; ++} ++ + int cmd_main(int argc UNUSED, const char *argv[] UNUSED) + { + if_test ("binary search with binsearch works") { +@@ t/unit-tests/t-reftable-basics.c: int cmd_main(int argc UNUSED, const char *argv[] UNUSED) + check_int(in, ==, out); + } + ++ if_test ("REFTABLE_ALLOC_GROW_OR_NULL works") { ++ int *arr = NULL; ++ size_t alloc = 0, old_alloc; ++ ++ REFTABLE_ALLOC_GROW_OR_NULL(arr, 1, alloc); ++ check(arr != NULL); ++ check_uint(alloc, >=, 1); ++ arr[0] = 42; ++ ++ old_alloc = alloc; ++ REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); ++ check(arr != NULL); ++ check_uint(alloc, >, old_alloc); ++ arr[alloc - 1] = 42; ++ ++ old_alloc = alloc; ++ reftable_set_alloc(malloc, realloc_stub, free); ++ REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); ++ check(arr == NULL); ++ check_uint(alloc, ==, 0); ++ reftable_set_alloc(malloc, realloc, free); ++ ++ reftable_free(arr); ++ } ++ + return test_done(); + } 2: bde2f0e4a5 ! 2: 62a1042825 reftable: fix allocation count on realloc error @@ reftable/basics.h: char *reftable_strdup(const char *str); - reftable_free(reftable_alloc_grow_or_null_orig_ptr); \ + size_t reftable_alloc_grow_or_null_alloc = alloc; \ + if (REFTABLE_ALLOC_GROW((x), (nr), reftable_alloc_grow_or_null_alloc)) { \ -+ reftable_free(x); \ ++ REFTABLE_FREE_AND_NULL(x); \ alloc = 0; \ + } else { \ + alloc = reftable_alloc_grow_or_null_alloc; \ } \ } while (0) + + ## t/unit-tests/t-reftable-basics.c ## +@@ t/unit-tests/t-reftable-basics.c: 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; 3: 7c9f044813 = 3: ed1a292622 reftable: handle realloc error in parse_names() 4: 3d9493f48a = 4: 916032657e t-reftable-merged: handle realloc errors -- 2.47.1