From 0d083bc81fdb6665333b4095baedefd90b652473 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Mon, 19 Oct 2026 12:15:28 -0400 Subject: [PATCH 1/2] Makefile: build the reftable record unit tests The Meson build includes the reftable record unit tests, but the Makefile does not. The suite was dropped from the Makefile when the test was converted to the clar framework in 2596bef5841f (2025-07-24). Include the reftable record unit test suite in the Makefile test target. Assisted-by: Claude Fable 5.1 Signed-off-by: Matthew Suozzo --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index a96be506b59f2d..66b7270fc0d2a4 100644 --- a/Makefile +++ b/Makefile @@ -1551,6 +1551,7 @@ CLAR_TEST_SUITES += u-reftable-block CLAR_TEST_SUITES += u-reftable-merged CLAR_TEST_SUITES += u-reftable-pq CLAR_TEST_SUITES += u-reftable-readwrite +CLAR_TEST_SUITES += u-reftable-record CLAR_TEST_SUITES += u-reftable-stack CLAR_TEST_SUITES += u-reftable-table CLAR_TEST_SUITES += u-reftable-tree From 8f4a8389d0c022de216d1086117fd23d2a8260a9 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Mon, 19 Oct 2026 12:15:28 -0400 Subject: [PATCH 2/2] reftable/basics: widen allocation size arguments to uintmax_t reftable_alloc_size() takes its arguments as size_t, but reftable_obj_record_decode() passes it a uint64_t count. On 32-bit platforms, a count wider than 32 bits is truncated before the overflow check, so the decoder can get a small allocation for a large count and write past its end. reftable_calloc() takes size_t arguments the same way. Make reftable_alloc_size() and reftable_calloc() take uintmax_t arguments, so the check sees the full count. Assisted-by: Claude Opus 5.5 Helped-by: Patrick Steinhardt Helped-by: Aniket Gupta Signed-off-by: Matthew Suozzo --- reftable/basics.c | 9 +++++---- reftable/basics.h | 5 +++-- t/unit-tests/u-reftable-basics.c | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/reftable/basics.c b/reftable/basics.c index f0442a46cf7c13..6103b72b447a4a 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -44,18 +44,19 @@ void reftable_free(void *p) free(p); } -void *reftable_calloc(size_t nelem, size_t elsize) +void *reftable_calloc(uintmax_t nelem, uintmax_t elsize) { + size_t size; void *p; - if (nelem && elsize > SIZE_MAX / nelem) + if (reftable_alloc_size(nelem, elsize, &size) < 0) return NULL; - p = reftable_malloc(nelem * elsize); + p = reftable_malloc(size); if (!p) return NULL; - memset(p, 0, nelem * elsize); + memset(p, 0, size); return p; } diff --git a/reftable/basics.h b/reftable/basics.h index e4b83b2b03ff8a..29d2b799cae028 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -184,10 +184,11 @@ size_t names_length(const char **names); void *reftable_malloc(size_t sz); void *reftable_realloc(void *p, size_t sz); void reftable_free(void *p); -void *reftable_calloc(size_t nelem, size_t elsize); +void *reftable_calloc(uintmax_t nelem, uintmax_t elsize); char *reftable_strdup(const char *str); -static inline int reftable_alloc_size(size_t nelem, size_t elsize, size_t *out) +static inline int reftable_alloc_size(uintmax_t nelem, uintmax_t elsize, + size_t *out) { if (nelem && elsize > SIZE_MAX / nelem) return -1; diff --git a/t/unit-tests/u-reftable-basics.c b/t/unit-tests/u-reftable-basics.c index c5d83b6714d2eb..37bf1ade5a45a3 100644 --- a/t/unit-tests/u-reftable-basics.c +++ b/t/unit-tests/u-reftable-basics.c @@ -200,6 +200,24 @@ void test_reftable_basics__put_get_be16(void) cl_assert_equal_i(in, out); } +void test_reftable_basics__alloc_size(void) +{ + size_t out; + + cl_assert_equal_i(reftable_alloc_size(3, 5, &out), 0); + cl_assert_equal_i(out, 15); + cl_assert(reftable_alloc_size(SIZE_MAX, 2, &out) < 0); + + /* Counts that do not fit in a size_t. */ + if (SIZE_MAX < UINTMAX_MAX) { + cl_assert(reftable_alloc_size((uintmax_t)SIZE_MAX + 1, + 1, &out) < 0); + cl_assert(reftable_alloc_size(1, (uintmax_t)SIZE_MAX + 1, + &out) < 0); + cl_assert(reftable_calloc((uintmax_t)SIZE_MAX + 1, 1) == NULL); + } +} + void test_reftable_basics__alloc_grow(void) { int *arr = NULL, *old_arr;