reftable/block: handle allocation failures

Handle allocation failures in `block_writer_init()` and `block_reader_init()`. This requires us to bubble up error codes into `writer_reinit_block_writer()`. Adapt call sites accordingly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Oct 2, 2024 at 12:56 UTC 2d5dbb37b284e3ca78137ec0f8a3d9ceef78877c
4 files changed +69 -29
reftable/block.c
+21 -2
@@ -52,6 +52,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
52 return -1;
53 if (is_restart) {
54 REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap);
55 + if (!w->restarts)
56 + return REFTABLE_OUT_OF_MEMORY_ERROR;
57 w->restarts[w->restart_len++] = w->next;
58 }
59
@@ -63,8 +65,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
65 return 0;
66 }
67
66 -void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
67 - uint32_t block_size, uint32_t header_off, int hash_size)
68 +int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
69 + uint32_t block_size, uint32_t header_off, int hash_size)
70 {
71 bw->buf = buf;
72 bw->hash_size = hash_size;
@@ -78,8 +80,12 @@ void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
80 bw->last_key.len = 0;
81 if (!bw->zstream) {
82 REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
83 + if (!bw->zstream)
84 + return REFTABLE_OUT_OF_MEMORY_ERROR;
85 deflateInit(bw->zstream, 9);
86 }
87 +
88 + return 0;
89 }
90
91 uint8_t block_writer_type(struct block_writer *bw)
@@ -163,6 +169,10 @@ int block_writer_finish(struct block_writer *w)
169 */
170 compressed_len = deflateBound(w->zstream, src_len);
171 REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap);
172 + if (!w->compressed) {
173 + ret = REFTABLE_OUT_OF_MEMORY_ERROR;
174 + return ret;
175 + }
176
177 w->zstream->next_out = w->compressed;
178 w->zstream->avail_out = compressed_len;
@@ -219,12 +229,21 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
229 /* Log blocks specify the *uncompressed* size in their header. */
230 REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
231 br->uncompressed_cap);
232 + if (!br->uncompressed_data) {
233 + err = REFTABLE_OUT_OF_MEMORY_ERROR;
234 + goto done;
235 + }
236
237 /* Copy over the block header verbatim. It's not compressed. */
238 memcpy(br->uncompressed_data, block->data, block_header_skip);
239
240 if (!br->zstream) {
241 REFTABLE_CALLOC_ARRAY(br->zstream, 1);
242 + if (!br->zstream) {
243 + err = REFTABLE_OUT_OF_MEMORY_ERROR;
244 + goto done;
245 + }
246 +
247 err = inflateInit(br->zstream);
248 } else {
249 err = inflateReset(br->zstream);
reftable/block.h
+2 -2
@@ -45,8 +45,8 @@ struct block_writer {
45 /*
46 * initializes the blockwriter to write `typ` entries, using `buf` as temporary
47 * storage. `buf` is not owned by the block_writer. */
48 -void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
49 - uint32_t block_size, uint32_t header_off, int hash_size);
48 +int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
49 + uint32_t block_size, uint32_t header_off, int hash_size);
50
51 /* returns the block type (eg. 'r' for ref records. */
52 uint8_t block_writer_type(struct block_writer *bw);
reftable/writer.c
+34 -17
@@ -102,19 +102,24 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
102 return header_size(writer_version(w));
103 }
104
105 -static void writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
105 +static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
106 {
107 - int block_start = 0;
108 - if (w->next == 0) {
107 + int block_start = 0, ret;
108 +
109 + if (w->next == 0)
110 block_start = header_size(writer_version(w));
110 - }
111
112 strbuf_reset(&w->last_key);
113 - block_writer_init(&w->block_writer_data, typ, w->block,
114 - w->opts.block_size, block_start,
115 - hash_size(w->opts.hash_id));
113 + ret = block_writer_init(&w->block_writer_data, typ, w->block,
114 + w->opts.block_size, block_start,
115 + hash_size(w->opts.hash_id));
116 + if (ret < 0)
117 + return ret;
118 +
119 w->block_writer = &w->block_writer_data;
120 w->block_writer->restart_interval = w->opts.restart_interval;
121 +
122 + return 0;
123 }
124
125 int reftable_writer_new(struct reftable_writer **out,
@@ -247,8 +252,11 @@ static int writer_add_record(struct reftable_writer *w,
252
253 strbuf_reset(&w->last_key);
254 strbuf_addbuf(&w->last_key, &key);
250 - if (!w->block_writer)
251 - writer_reinit_block_writer(w, reftable_record_type(rec));
255 + if (!w->block_writer) {
256 + err = writer_reinit_block_writer(w, reftable_record_type(rec));
257 + if (err < 0)
258 + goto done;
259 + }
260
261 if (block_writer_type(w->block_writer) != reftable_record_type(rec))
262 BUG("record of type %d added to writer of type %d",
@@ -271,7 +279,9 @@ static int writer_add_record(struct reftable_writer *w,
279 err = writer_flush_block(w);
280 if (err < 0)
281 goto done;
274 - writer_reinit_block_writer(w, reftable_record_type(rec));
282 + err = writer_reinit_block_writer(w, reftable_record_type(rec));
283 + if (err < 0)
284 + goto done;
285
286 /*
287 * Try to add the record to the writer again. If this still fails then
@@ -461,7 +471,9 @@ static int writer_finish_section(struct reftable_writer *w)
471
472 max_level++;
473 index_start = w->next;
464 - writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
474 + err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
475 + if (err < 0)
476 + return err;
477
478 idx = w->index;
479 idx_len = w->index_len;
@@ -555,7 +567,10 @@ static void write_object_record(void *void_arg, void *key)
567 if (arg->err < 0)
568 goto done;
569
558 - writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
570 + arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
571 + if (arg->err < 0)
572 + goto done;
573 +
574 arg->err = block_writer_add(arg->w->block_writer, &rec);
575 if (arg->err == 0)
576 goto done;
@@ -584,16 +599,18 @@ static int writer_dump_object_index(struct reftable_writer *w)
599 struct common_prefix_arg common = {
600 .max = 1, /* obj_id_len should be >= 2. */
601 };
587 - if (w->obj_index_tree) {
602 + int err;
603 +
604 + if (w->obj_index_tree)
605 infix_walk(w->obj_index_tree, &update_common, &common);
589 - }
606 w->stats.object_id_len = common.max + 1;
607
592 - writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
608 + err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
609 + if (err < 0)
610 + return err;
611
594 - if (w->obj_index_tree) {
612 + if (w->obj_index_tree)
613 infix_walk(w->obj_index_tree, &write_object_record, &closure);
596 - }
614
615 if (closure.err < 0)
616 return closure.err;
t/unit-tests/t-reftable-block.c
+12 -8
@@ -34,8 +34,9 @@ static void t_ref_block_read_write(void)
34 REFTABLE_CALLOC_ARRAY(block.data, block_size);
35 block.len = block_size;
36 block_source_from_strbuf(&block.source ,&buf);
37 - block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
38 - header_off, hash_size(GIT_SHA1_FORMAT_ID));
37 + ret = block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size,
38 + header_off, hash_size(GIT_SHA1_FORMAT_ID));
39 + check(!ret);
40
41 rec.u.ref.refname = (char *) "";
42 rec.u.ref.value_type = REFTABLE_REF_DELETION;
@@ -126,8 +127,9 @@ static void t_log_block_read_write(void)
127 REFTABLE_CALLOC_ARRAY(block.data, block_size);
128 block.len = block_size;
129 block_source_from_strbuf(&block.source ,&buf);
129 - block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
130 - header_off, hash_size(GIT_SHA1_FORMAT_ID));
130 + ret = block_writer_init(&bw, BLOCK_TYPE_LOG, block.data, block_size,
131 + header_off, hash_size(GIT_SHA1_FORMAT_ID));
132 + check(!ret);
133
134 for (i = 0; i < N; i++) {
135 rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i);
@@ -214,8 +216,9 @@ static void t_obj_block_read_write(void)
216 REFTABLE_CALLOC_ARRAY(block.data, block_size);
217 block.len = block_size;
218 block_source_from_strbuf(&block.source, &buf);
217 - block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
218 - header_off, hash_size(GIT_SHA1_FORMAT_ID));
219 + ret = block_writer_init(&bw, BLOCK_TYPE_OBJ, block.data, block_size,
220 + header_off, hash_size(GIT_SHA1_FORMAT_ID));
221 + check(!ret);
222
223 for (i = 0; i < N; i++) {
224 uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated;
@@ -296,8 +299,9 @@ static void t_index_block_read_write(void)
299 REFTABLE_CALLOC_ARRAY(block.data, block_size);
300 block.len = block_size;
301 block_source_from_strbuf(&block.source, &buf);
299 - block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
300 - header_off, hash_size(GIT_SHA1_FORMAT_ID));
302 + ret = block_writer_init(&bw, BLOCK_TYPE_INDEX, block.data, block_size,
303 + header_off, hash_size(GIT_SHA1_FORMAT_ID));
304 + check(!ret);
305
306 for (i = 0; i < N; i++) {
307 strbuf_init(&recs[i].u.idx.last_key, 9);