reftable/basics: stop using `st_mult()` in array allocators

We're using `st_mult()` as part of our macro helpers that allocate arrays. This is bad due two two reasons: - `st_mult()` causes us to die in case the multiplication overflows. - `st_mult()` ties us to the Git codebase. Refactor the code to instead detect overflows manually and return an error in such cases. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Feb 18, 2025 at 10:20 UTC 6e3ea71639a3541523f2be8f950325c8a0aa6768
1 file changed +32 -4
reftable/basics.h
+32 -4
@@ -117,18 +117,46 @@ void reftable_free(void *p);
117 void *reftable_calloc(size_t nelem, size_t elsize);
118 char *reftable_strdup(const char *str);
119
120 -#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
120 +static inline int reftable_alloc_size(size_t nelem, size_t elsize, size_t *out)
121 +{
122 + if (nelem && elsize > SIZE_MAX / nelem)
123 + return -1;
124 + *out = nelem * elsize;
125 + return 0;
126 +}
127 +
128 +#define REFTABLE_ALLOC_ARRAY(x, alloc) do { \
129 + size_t alloc_size; \
130 + if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \
131 + errno = ENOMEM; \
132 + (x) = NULL; \
133 + } else { \
134 + (x) = reftable_malloc(alloc_size); \
135 + } \
136 + } while (0)
137 #define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
122 -#define REFTABLE_REALLOC_ARRAY(x, alloc) (x) = reftable_realloc((x), st_mult(sizeof(*(x)), (alloc)))
138 +#define REFTABLE_REALLOC_ARRAY(x, alloc) do { \
139 + size_t alloc_size; \
140 + if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \
141 + errno = ENOMEM; \
142 + (x) = NULL; \
143 + } else { \
144 + (x) = reftable_realloc((x), alloc_size); \
145 + } \
146 + } while (0)
147
148 static inline void *reftable_alloc_grow(void *p, size_t nelem, size_t elsize,
149 size_t *allocp)
150 {
151 void *new_p;
128 - size_t alloc = *allocp * 2 + 1;
152 + size_t alloc = *allocp * 2 + 1, alloc_bytes;
153 if (alloc < nelem)
154 alloc = nelem;
131 - new_p = reftable_realloc(p, st_mult(elsize, alloc));
155 + if (reftable_alloc_size(elsize, alloc, &alloc_bytes) < 0) {
156 + errno = ENOMEM;
157 + return p;
158 + }
159 + new_p = reftable_realloc(p, alloc_bytes);
160 if (!new_p)
161 return p;
162 *allocp = alloc;