reftable: introduce macros to allocate arrays

Similar to the preceding commit, let's carry over macros to allocate arrays with `REFTABLE_ALLOC_ARRAY()` and `REFTABLE_CALLOC_ARRAY()`. This requires us to change the signature of `reftable_calloc()`, which only takes a single argument right now and thus puts the burden on the caller to calculate the final array's size. This is a net improvement though as it means that we can now provide proper overflow checks when multiplying the array size with the member size. Convert callsites of `reftable_calloc()` to the new signature and start using the new macros where possible. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Feb 6, 2024 at 07:35 UTC b4ff12c8eefff9cba73ba3cb7492111adfa31d87
16 files changed +68 -61
reftable/basics.h
+3 -1
@@ -51,8 +51,10 @@ int names_length(char **names);
51 void *reftable_malloc(size_t sz);
52 void *reftable_realloc(void *p, size_t sz);
53 void reftable_free(void *p);
54 -void *reftable_calloc(size_t sz);
54 +void *reftable_calloc(size_t nelem, size_t elsize);
55
56 +#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
57 +#define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
58 #define REFTABLE_REALLOC_ARRAY(x, alloc) (x) = reftable_realloc((x), st_mult(sizeof(*(x)), (alloc)))
59 #define REFTABLE_ALLOC_GROW(x, nr, alloc) \
60 do { \
reftable/block.c
+6 -4
@@ -143,8 +143,10 @@ int block_writer_finish(struct block_writer *w)
143 int block_header_skip = 4 + w->header_off;
144 uLongf src_len = w->next - block_header_skip;
145 uLongf dest_cap = src_len * 1.001 + 12;
146 + uint8_t *compressed;
147 +
148 + REFTABLE_ALLOC_ARRAY(compressed, dest_cap);
149
147 - uint8_t *compressed = reftable_malloc(dest_cap);
150 while (1) {
151 uLongf out_dest_len = dest_cap;
152 int zresult = compress2(compressed, &out_dest_len,
@@ -201,9 +203,9 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
203 uLongf dst_len = sz - block_header_skip; /* total size of dest
204 buffer. */
205 uLongf src_len = block->len - block_header_skip;
204 - /* Log blocks specify the *uncompressed* size in their header.
205 - */
206 - uncompressed = reftable_malloc(sz);
206 +
207 + /* Log blocks specify the *uncompressed* size in their header. */
208 + REFTABLE_ALLOC_ARRAY(uncompressed, sz);
209
210 /* Copy over the block header verbatim. It's not compressed. */
211 memcpy(uncompressed, block->data, block_header_skip);
reftable/block_test.c
+1 -1
@@ -36,7 +36,7 @@ static void test_block_read_write(void)
36 int j = 0;
37 struct strbuf want = STRBUF_INIT;
38
39 - block.data = reftable_calloc(block_size);
39 + REFTABLE_CALLOC_ARRAY(block.data, block_size);
40 block.len = block_size;
41 block.source = malloc_block_source();
42 block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
reftable/blocksource.c
+2 -2
@@ -29,7 +29,7 @@ static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
29 {
30 struct strbuf *b = v;
31 assert(off + size <= b->len);
32 - dest->data = reftable_calloc(size);
32 + REFTABLE_CALLOC_ARRAY(dest->data, size);
33 memcpy(dest->data, b->buf + off, size);
34 dest->len = size;
35 return size;
@@ -132,7 +132,7 @@ int reftable_block_source_from_file(struct reftable_block_source *bs,
132 return REFTABLE_IO_ERROR;
133 }
134
135 - p = reftable_calloc(sizeof(*p));
135 + REFTABLE_CALLOC_ARRAY(p, 1);
136 p->size = st.st_size;
137 p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
138 close(fd);
reftable/iter.c
+1 -2
@@ -160,8 +160,7 @@ int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
160 int oid_len, uint64_t *offsets, int offset_len)
161 {
162 struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
163 - struct indexed_table_ref_iter *itr =
164 - reftable_calloc(sizeof(struct indexed_table_ref_iter));
163 + struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
164 int err = 0;
165
166 *itr = empty;
reftable/merged.c
+2 -2
@@ -190,7 +190,7 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
190 }
191 }
192
193 - m = reftable_calloc(sizeof(struct reftable_merged_table));
193 + REFTABLE_CALLOC_ARRAY(m, 1);
194 m->stack = stack;
195 m->stack_len = n;
196 m->min = first_min;
@@ -240,7 +240,7 @@ static int merged_table_seek_record(struct reftable_merged_table *mt,
240 struct reftable_record *rec)
241 {
242 struct reftable_iterator *iters = reftable_calloc(
243 - sizeof(struct reftable_iterator) * mt->stack_len);
243 + mt->stack_len, sizeof(*iters));
244 struct merged_iter merged = {
245 .stack = iters,
246 .typ = reftable_record_type(rec),
reftable/merged_test.c
+13 -9
@@ -93,10 +93,12 @@ merged_table_from_records(struct reftable_ref_record **refs,
93 int i = 0;
94 struct reftable_merged_table *mt = NULL;
95 int err;
96 - struct reftable_table *tabs =
97 - reftable_calloc(n * sizeof(struct reftable_table));
98 - *readers = reftable_calloc(n * sizeof(struct reftable_reader *));
99 - *source = reftable_calloc(n * sizeof(**source));
96 + struct reftable_table *tabs;
97 +
98 + REFTABLE_CALLOC_ARRAY(tabs, n);
99 + REFTABLE_CALLOC_ARRAY(*readers, n);
100 + REFTABLE_CALLOC_ARRAY(*source, n);
101 +
102 for (i = 0; i < n; i++) {
103 write_test_table(&buf[i], refs[i], sizes[i]);
104 block_source_from_strbuf(&(*source)[i], &buf[i]);
@@ -266,10 +268,12 @@ merged_table_from_log_records(struct reftable_log_record **logs,
268 int i = 0;
269 struct reftable_merged_table *mt = NULL;
270 int err;
269 - struct reftable_table *tabs =
270 - reftable_calloc(n * sizeof(struct reftable_table));
271 - *readers = reftable_calloc(n * sizeof(struct reftable_reader *));
272 - *source = reftable_calloc(n * sizeof(**source));
271 + struct reftable_table *tabs;
272 +
273 + REFTABLE_CALLOC_ARRAY(tabs, n);
274 + REFTABLE_CALLOC_ARRAY(*readers, n);
275 + REFTABLE_CALLOC_ARRAY(*source, n);
276 +
277 for (i = 0; i < n; i++) {
278 write_test_log_table(&buf[i], logs[i], sizes[i], i + 1);
279 block_source_from_strbuf(&(*source)[i], &buf[i]);
@@ -412,7 +416,7 @@ static void test_default_write_opts(void)
416 };
417 int err;
418 struct reftable_block_source source = { NULL };
415 - struct reftable_table *tab = reftable_calloc(sizeof(*tab) * 1);
419 + struct reftable_table *tab = reftable_calloc(1, sizeof(*tab));
420 uint32_t hash_id;
421 struct reftable_reader *rd = NULL;
422 struct reftable_merged_table *merged = NULL;
reftable/publicbasics.c
+2 -1
@@ -37,8 +37,9 @@ void reftable_free(void *p)
37 free(p);
38 }
39
40 -void *reftable_calloc(size_t sz)
40 +void *reftable_calloc(size_t nelem, size_t elsize)
41 {
42 + size_t sz = st_mult(nelem, elsize);
43 void *p = reftable_malloc(sz);
44 memset(p, 0, sz);
45 return p;
reftable/reader.c
+3 -5
@@ -539,8 +539,7 @@ static int reader_seek_indexed(struct reftable_reader *r,
539
540 if (err == 0) {
541 struct table_iter empty = TABLE_ITER_INIT;
542 - struct table_iter *malloced =
543 - reftable_calloc(sizeof(struct table_iter));
542 + struct table_iter *malloced = reftable_calloc(1, sizeof(*malloced));
543 *malloced = empty;
544 table_iter_copy_from(malloced, &next);
545 iterator_from_table_iter(it, malloced);
@@ -635,8 +634,7 @@ void reader_close(struct reftable_reader *r)
634 int reftable_new_reader(struct reftable_reader **p,
635 struct reftable_block_source *src, char const *name)
636 {
638 - struct reftable_reader *rd =
639 - reftable_calloc(sizeof(struct reftable_reader));
637 + struct reftable_reader *rd = reftable_calloc(1, sizeof(*rd));
638 int err = init_reader(rd, src, name);
639 if (err == 0) {
640 *p = rd;
@@ -711,7 +709,7 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
709 uint8_t *oid)
710 {
711 struct table_iter ti_empty = TABLE_ITER_INIT;
714 - struct table_iter *ti = reftable_calloc(sizeof(struct table_iter));
712 + struct table_iter *ti = reftable_calloc(1, sizeof(*ti));
713 struct filtering_ref_iterator *filter = NULL;
714 struct filtering_ref_iterator empty = FILTERING_REF_ITERATOR_INIT;
715 int oid_len = hash_size(r->hash_id);
reftable/readwrite_test.c
+5 -3
@@ -56,7 +56,9 @@ static void write_table(char ***names, struct strbuf *buf, int N,
56 int i = 0, n;
57 struct reftable_log_record log = { NULL };
58 const struct reftable_stats *stats = NULL;
59 - *names = reftable_calloc(sizeof(char *) * (N + 1));
59 +
60 + REFTABLE_CALLOC_ARRAY(*names, N + 1);
61 +
62 reftable_writer_set_limits(w, update_index, update_index);
63 for (i = 0; i < N; i++) {
64 char name[100];
@@ -188,7 +190,7 @@ static void test_log_overflow(void)
190 static void test_log_write_read(void)
191 {
192 int N = 2;
191 - char **names = reftable_calloc(sizeof(char *) * (N + 1));
193 + char **names = reftable_calloc(N + 1, sizeof(*names));
194 int err;
195 struct reftable_write_options opts = {
196 .block_size = 256,
@@ -519,7 +521,7 @@ static void test_table_read_write_seek_index(void)
521 static void test_table_refs_for(int indexed)
522 {
523 int N = 50;
522 - char **want_names = reftable_calloc(sizeof(char *) * (N + 1));
524 + char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
525 int want_names_len = 0;
526 uint8_t want_hash[GIT_SHA1_RAWSZ];
527
reftable/record.c
+8 -6
@@ -497,12 +497,13 @@ static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
497 (const struct reftable_obj_record *)src_rec;
498
499 reftable_obj_record_release(obj);
500 - obj->hash_prefix = reftable_malloc(src->hash_prefix_len);
500 +
501 + REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
502 obj->hash_prefix_len = src->hash_prefix_len;
503 if (src->hash_prefix_len)
504 memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
505
505 - obj->offsets = reftable_malloc(src->offset_len * sizeof(uint64_t));
506 + REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
507 obj->offset_len = src->offset_len;
508 COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
509 }
@@ -559,7 +560,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
560 int n = 0;
561 uint64_t last;
562 int j;
562 - r->hash_prefix = reftable_malloc(key.len);
563 +
564 + REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
565 memcpy(r->hash_prefix, key.buf, key.len);
566 r->hash_prefix_len = key.len;
567
@@ -577,7 +579,7 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
579 if (count == 0)
580 return start.len - in.len;
581
580 - r->offsets = reftable_malloc(count * sizeof(uint64_t));
582 + REFTABLE_ALLOC_ARRAY(r->offsets, count);
583 r->offset_len = count;
584
585 n = get_var_int(&r->offsets[0], &in);
@@ -715,12 +717,12 @@ static void reftable_log_record_copy_from(void *rec, const void *src_rec,
717 }
718
719 if (dst->value.update.new_hash) {
718 - dst->value.update.new_hash = reftable_malloc(hash_size);
720 + REFTABLE_ALLOC_ARRAY(dst->value.update.new_hash, hash_size);
721 memcpy(dst->value.update.new_hash,
722 src->value.update.new_hash, hash_size);
723 }
724 if (dst->value.update.old_hash) {
723 - dst->value.update.old_hash = reftable_malloc(hash_size);
725 + REFTABLE_ALLOC_ARRAY(dst->value.update.old_hash, hash_size);
726 memcpy(dst->value.update.old_hash,
727 src->value.update.old_hash, hash_size);
728 }
reftable/record_test.c
+2 -2
@@ -231,8 +231,8 @@ static void test_reftable_log_record_roundtrip(void)
231 .value_type = REFTABLE_LOG_UPDATE,
232 .value = {
233 .update = {
234 - .new_hash = reftable_calloc(GIT_SHA1_RAWSZ),
235 - .old_hash = reftable_calloc(GIT_SHA1_RAWSZ),
234 + .new_hash = reftable_calloc(GIT_SHA1_RAWSZ, 1),
235 + .old_hash = reftable_calloc(GIT_SHA1_RAWSZ, 1),
236 .name = xstrdup("old name"),
237 .email = xstrdup("old@email"),
238 .message = xstrdup("old message"),
reftable/refname.c
+2 -2
@@ -140,8 +140,8 @@ int validate_ref_record_addition(struct reftable_table tab,
140 {
141 struct modification mod = {
142 .tab = tab,
143 - .add = reftable_calloc(sizeof(char *) * sz),
144 - .del = reftable_calloc(sizeof(char *) * sz),
143 + .add = reftable_calloc(sz, sizeof(*mod.add)),
144 + .del = reftable_calloc(sz, sizeof(*mod.del)),
145 };
146 int i = 0;
147 int err = 0;
reftable/stack.c
+13 -15
@@ -50,8 +50,7 @@ static ssize_t reftable_fd_write(void *arg, const void *data, size_t sz)
50 int reftable_new_stack(struct reftable_stack **dest, const char *dir,
51 struct reftable_write_options config)
52 {
53 - struct reftable_stack *p =
54 - reftable_calloc(sizeof(struct reftable_stack));
53 + struct reftable_stack *p = reftable_calloc(1, sizeof(*p));
54 struct strbuf list_file_name = STRBUF_INIT;
55 int err = 0;
56
@@ -94,7 +93,7 @@ static int fd_read_lines(int fd, char ***namesp)
93 goto done;
94 }
95
97 - buf = reftable_malloc(size + 1);
96 + REFTABLE_ALLOC_ARRAY(buf, size + 1);
97 if (read_in_full(fd, buf, size) != size) {
98 err = REFTABLE_IO_ERROR;
99 goto done;
@@ -114,7 +113,7 @@ int read_lines(const char *filename, char ***namesp)
113 int err = 0;
114 if (fd < 0) {
115 if (errno == ENOENT) {
117 - *namesp = reftable_calloc(sizeof(char *));
116 + REFTABLE_CALLOC_ARRAY(*namesp, 1);
117 return 0;
118 }
119
@@ -191,8 +190,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
190 static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
191 int cur_len)
192 {
194 - struct reftable_reader **cur =
195 - reftable_calloc(sizeof(struct reftable_reader *) * cur_len);
193 + struct reftable_reader **cur = reftable_calloc(cur_len, sizeof(*cur));
194 int i = 0;
195 for (i = 0; i < cur_len; i++) {
196 cur[i] = st->readers[i];
@@ -208,9 +206,9 @@ static int reftable_stack_reload_once(struct reftable_stack *st, char **names,
206 int err = 0;
207 int names_len = names_length(names);
208 struct reftable_reader **new_readers =
211 - reftable_calloc(sizeof(struct reftable_reader *) * names_len);
209 + reftable_calloc(names_len, sizeof(*new_readers));
210 struct reftable_table *new_tables =
213 - reftable_calloc(sizeof(struct reftable_table) * names_len);
211 + reftable_calloc(names_len, sizeof(*new_tables));
212 int new_readers_len = 0;
213 struct reftable_merged_table *new_merged = NULL;
214 struct strbuf table_path = STRBUF_INIT;
@@ -344,7 +342,7 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
342 goto out;
343 }
344
347 - names = reftable_calloc(sizeof(char *));
345 + REFTABLE_CALLOC_ARRAY(names, 1);
346 } else {
347 err = fd_read_lines(fd, &names);
348 if (err < 0)
@@ -686,7 +684,7 @@ int reftable_stack_new_addition(struct reftable_addition **dest,
684 {
685 int err = 0;
686 struct reftable_addition empty = REFTABLE_ADDITION_INIT;
689 - *dest = reftable_calloc(sizeof(**dest));
687 + REFTABLE_CALLOC_ARRAY(*dest, 1);
688 **dest = empty;
689 err = reftable_stack_init_addition(*dest, st);
690 if (err) {
@@ -871,7 +869,7 @@ static int stack_write_compact(struct reftable_stack *st,
869 {
870 int subtabs_len = last - first + 1;
871 struct reftable_table *subtabs = reftable_calloc(
874 - sizeof(struct reftable_table) * (last - first + 1));
872 + last - first + 1, sizeof(*subtabs));
873 struct reftable_merged_table *mt = NULL;
874 int err = 0;
875 struct reftable_iterator it = { NULL };
@@ -979,9 +977,9 @@ static int stack_compact_range(struct reftable_stack *st, int first, int last,
977 int compact_count = last - first + 1;
978 char **listp = NULL;
979 char **delete_on_success =
982 - reftable_calloc(sizeof(char *) * (compact_count + 1));
980 + reftable_calloc(compact_count + 1, sizeof(*delete_on_success));
981 char **subtable_locks =
984 - reftable_calloc(sizeof(char *) * (compact_count + 1));
982 + reftable_calloc(compact_count + 1, sizeof(*subtable_locks));
983 int i = 0;
984 int j = 0;
985 int is_empty_table = 0;
@@ -1204,7 +1202,7 @@ int fastlog2(uint64_t sz)
1202
1203 struct segment *sizes_to_segments(int *seglen, uint64_t *sizes, int n)
1204 {
1207 - struct segment *segs = reftable_calloc(sizeof(struct segment) * n);
1205 + struct segment *segs = reftable_calloc(n, sizeof(*segs));
1206 int next = 0;
1207 struct segment cur = { 0 };
1208 int i = 0;
@@ -1268,7 +1266,7 @@ struct segment suggest_compaction_segment(uint64_t *sizes, int n)
1266 static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
1267 {
1268 uint64_t *sizes =
1271 - reftable_calloc(sizeof(uint64_t) * st->merged->stack_len);
1269 + reftable_calloc(st->merged->stack_len, sizeof(*sizes));
1270 int version = (st->config.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
1271 int overhead = header_size(version) - 1;
1272 int i = 0;
reftable/tree.c
+2 -2
@@ -20,8 +20,8 @@ struct tree_node *tree_search(void *key, struct tree_node **rootp,
20 if (!insert) {
21 return NULL;
22 } else {
23 - struct tree_node *n =
24 - reftable_calloc(sizeof(struct tree_node));
23 + struct tree_node *n;
24 + REFTABLE_CALLOC_ARRAY(n, 1);
25 n->key = key;
26 *rootp = n;
27 return *rootp;
reftable/writer.c
+3 -4
@@ -49,7 +49,7 @@ static int padded_write(struct reftable_writer *w, uint8_t *data, size_t len,
49 {
50 int n = 0;
51 if (w->pending_padding > 0) {
52 - uint8_t *zeroed = reftable_calloc(w->pending_padding);
52 + uint8_t *zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
53 int n = w->write(w->write_arg, zeroed, w->pending_padding);
54 if (n < 0)
55 return n;
@@ -123,8 +123,7 @@ struct reftable_writer *
123 reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
124 void *writer_arg, struct reftable_write_options *opts)
125 {
126 - struct reftable_writer *wp =
127 - reftable_calloc(sizeof(struct reftable_writer));
126 + struct reftable_writer *wp = reftable_calloc(1, sizeof(*wp));
127 strbuf_init(&wp->block_writer_data.last_key, 0);
128 options_set_defaults(opts);
129 if (opts->block_size >= (1 << 24)) {
@@ -132,7 +131,7 @@ reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
131 abort();
132 }
133 wp->last_key = reftable_empty_strbuf;
135 - wp->block = reftable_calloc(opts->block_size);
134 + REFTABLE_CALLOC_ARRAY(wp->block, opts->block_size);
135 wp->write = writer_func;
136 wp->write_arg = writer_arg;
137 wp->opts = *opts;