Skip to content

Commit 5575c71

Browse files
committed
Merge branch 'ps/reftable-alloc-failures'
The reftable library is now prepared to expect that the memory allocation function given to it may fail to allocate and to deal with such an error. * ps/reftable-alloc-failures: (26 commits) reftable/basics: fix segfault when growing `names` array fails reftable/basics: ban standard allocator functions reftable: introduce `REFTABLE_FREE_AND_NULL()` reftable: fix calls to free(3P) reftable: handle trivial allocation failures reftable/tree: handle allocation failures reftable/pq: handle allocation failures when adding entries reftable/block: handle allocation failures reftable/blocksource: handle allocation failures reftable/iter: handle allocation failures when creating indexed table iter reftable/stack: handle allocation failures in auto compaction reftable/stack: handle allocation failures in `stack_compact_range()` reftable/stack: handle allocation failures in `reftable_new_stack()` reftable/stack: handle allocation failures on reload reftable/reader: handle allocation failures in `reader_init_iter()` reftable/reader: handle allocation failures for unindexed reader reftable/merged: handle allocation failures in `merged_table_init_iter()` reftable/writer: handle allocation failures in `reftable_new_writer()` reftable/writer: handle allocation failures in `writer_index_hash()` reftable/record: handle allocation failures when decoding records ...
2 parents 7994503 + 2179b5c commit 5575c71

38 files changed

+893
-408
lines changed

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2717,7 +2717,6 @@ REFTABLE_OBJS += reftable/error.o
27172717
REFTABLE_OBJS += reftable/block.o
27182718
REFTABLE_OBJS += reftable/blocksource.o
27192719
REFTABLE_OBJS += reftable/iter.o
2720-
REFTABLE_OBJS += reftable/publicbasics.o
27212720
REFTABLE_OBJS += reftable/merged.o
27222721
REFTABLE_OBJS += reftable/pq.o
27232722
REFTABLE_OBJS += reftable/reader.o

refs/reftable-backend.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,7 +1320,9 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
13201320
struct reftable_log_record log = {0};
13211321
struct reftable_iterator it = {0};
13221322

1323-
reftable_stack_init_log_iterator(arg->stack, &it);
1323+
ret = reftable_stack_init_log_iterator(arg->stack, &it);
1324+
if (ret < 0)
1325+
goto done;
13241326

13251327
/*
13261328
* When deleting refs we also delete all reflog entries
@@ -1690,7 +1692,10 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
16901692
* copy over all log entries from the old reflog. Last but not least,
16911693
* when renaming we also have to delete all the old reflog entries.
16921694
*/
1693-
reftable_stack_init_log_iterator(arg->stack, &it);
1695+
ret = reftable_stack_init_log_iterator(arg->stack, &it);
1696+
if (ret < 0)
1697+
goto done;
1698+
16941699
ret = reftable_iterator_seek_log(&it, arg->oldname);
16951700
if (ret < 0)
16961701
goto done;
@@ -1911,7 +1916,10 @@ static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftabl
19111916
if (ret < 0)
19121917
goto done;
19131918

1914-
reftable_stack_init_log_iterator(stack, &iter->iter);
1919+
ret = reftable_stack_init_log_iterator(stack, &iter->iter);
1920+
if (ret < 0)
1921+
goto done;
1922+
19151923
ret = reftable_iterator_seek_log(&iter->iter, "");
19161924
if (ret < 0)
19171925
goto done;
@@ -1978,7 +1986,10 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
19781986
if (refs->err < 0)
19791987
return refs->err;
19801988

1981-
reftable_stack_init_log_iterator(stack, &it);
1989+
ret = reftable_stack_init_log_iterator(stack, &it);
1990+
if (ret < 0)
1991+
goto done;
1992+
19821993
ret = reftable_iterator_seek_log(&it, refname);
19831994
while (!ret) {
19841995
ret = reftable_iterator_next_log(&it, &log);
@@ -1994,6 +2005,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
19942005
break;
19952006
}
19962007

2008+
done:
19972009
reftable_log_record_release(&log);
19982010
reftable_iterator_destroy(&it);
19992011
return ret;
@@ -2015,7 +2027,10 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
20152027
if (refs->err < 0)
20162028
return refs->err;
20172029

2018-
reftable_stack_init_log_iterator(stack, &it);
2030+
ret = reftable_stack_init_log_iterator(stack, &it);
2031+
if (ret < 0)
2032+
goto done;
2033+
20192034
ret = reftable_iterator_seek_log(&it, refname);
20202035
while (!ret) {
20212036
struct reftable_log_record log = {0};
@@ -2065,7 +2080,10 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
20652080
if (ret < 0)
20662081
goto done;
20672082

2068-
reftable_stack_init_log_iterator(stack, &it);
2083+
ret = reftable_stack_init_log_iterator(stack, &it);
2084+
if (ret < 0)
2085+
goto done;
2086+
20692087
ret = reftable_iterator_seek_log(&it, refname);
20702088
if (ret < 0)
20712089
goto done;
@@ -2171,7 +2189,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
21712189

21722190
reftable_writer_set_limits(writer, ts, ts);
21732191

2174-
reftable_stack_init_log_iterator(arg->stack, &it);
2192+
ret = reftable_stack_init_log_iterator(arg->stack, &it);
2193+
if (ret < 0)
2194+
goto out;
21752195

21762196
/*
21772197
* In order to delete a table we need to delete all reflog entries one
@@ -2195,6 +2215,7 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
21952215
ret = reftable_writer_add_log(writer, &tombstone);
21962216
}
21972217

2218+
out:
21982219
reftable_log_record_release(&log);
21992220
reftable_iterator_destroy(&it);
22002221
return ret;
@@ -2333,7 +2354,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
23332354
if (ret < 0)
23342355
goto done;
23352356

2336-
reftable_stack_init_log_iterator(stack, &it);
2357+
ret = reftable_stack_init_log_iterator(stack, &it);
2358+
if (ret < 0)
2359+
goto done;
23372360

23382361
ret = reftable_iterator_seek_log(&it, refname);
23392362
if (ret < 0)

reftable/basics.c

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,68 @@ license that can be found in the LICENSE file or at
66
https://developers.google.com/open-source/licenses/bsd
77
*/
88

9+
#define REFTABLE_ALLOW_BANNED_ALLOCATORS
910
#include "basics.h"
11+
#include "reftable-basics.h"
12+
13+
static void *(*reftable_malloc_ptr)(size_t sz);
14+
static void *(*reftable_realloc_ptr)(void *, size_t);
15+
static void (*reftable_free_ptr)(void *);
16+
17+
void *reftable_malloc(size_t sz)
18+
{
19+
if (reftable_malloc_ptr)
20+
return (*reftable_malloc_ptr)(sz);
21+
return malloc(sz);
22+
}
23+
24+
void *reftable_realloc(void *p, size_t sz)
25+
{
26+
if (reftable_realloc_ptr)
27+
return (*reftable_realloc_ptr)(p, sz);
28+
return realloc(p, sz);
29+
}
30+
31+
void reftable_free(void *p)
32+
{
33+
if (reftable_free_ptr)
34+
reftable_free_ptr(p);
35+
else
36+
free(p);
37+
}
38+
39+
void *reftable_calloc(size_t nelem, size_t elsize)
40+
{
41+
void *p;
42+
43+
if (nelem && elsize > SIZE_MAX / nelem)
44+
return NULL;
45+
46+
p = reftable_malloc(nelem * elsize);
47+
if (!p)
48+
return NULL;
49+
50+
memset(p, 0, nelem * elsize);
51+
return p;
52+
}
53+
54+
char *reftable_strdup(const char *str)
55+
{
56+
size_t len = strlen(str);
57+
char *result = reftable_malloc(len + 1);
58+
if (!result)
59+
return NULL;
60+
memcpy(result, str, len + 1);
61+
return result;
62+
}
63+
64+
void reftable_set_alloc(void *(*malloc)(size_t),
65+
void *(*realloc)(void *, size_t), void (*free)(void *))
66+
{
67+
reftable_malloc_ptr = malloc;
68+
reftable_realloc_ptr = realloc;
69+
reftable_free_ptr = free;
70+
}
1071

1172
void put_be24(uint8_t *out, uint32_t i)
1273
{
@@ -75,14 +136,14 @@ size_t names_length(const char **names)
75136
return p - names;
76137
}
77138

78-
void parse_names(char *buf, int size, char ***namesp)
139+
char **parse_names(char *buf, int size)
79140
{
80141
char **names = NULL;
81142
size_t names_cap = 0;
82143
size_t names_len = 0;
83-
84144
char *p = buf;
85145
char *end = buf + size;
146+
86147
while (p < end) {
87148
char *next = strchr(p, '\n');
88149
if (next && next < end) {
@@ -91,15 +152,29 @@ void parse_names(char *buf, int size, char ***namesp)
91152
next = end;
92153
}
93154
if (p < next) {
94-
REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap);
95-
names[names_len++] = xstrdup(p);
155+
char **names_grown = names;
156+
REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap);
157+
if (!names_grown)
158+
goto err;
159+
names = names_grown;
160+
161+
names[names_len] = reftable_strdup(p);
162+
if (!names[names_len++])
163+
goto err;
96164
}
97165
p = next + 1;
98166
}
99167

100168
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
101169
names[names_len] = NULL;
102-
*namesp = names;
170+
171+
return names;
172+
173+
err:
174+
for (size_t i = 0; i < names_len; i++)
175+
reftable_free(names[i]);
176+
reftable_free(names);
177+
return NULL;
103178
}
104179

105180
int names_equal(const char **a, const char **b)
@@ -121,3 +196,15 @@ int common_prefix_size(struct strbuf *a, struct strbuf *b)
121196

122197
return p;
123198
}
199+
200+
int hash_size(uint32_t id)
201+
{
202+
switch (id) {
203+
case 0:
204+
case GIT_SHA1_FORMAT_ID:
205+
return GIT_SHA1_RAWSZ;
206+
case GIT_SHA256_FORMAT_ID:
207+
return GIT_SHA256_RAWSZ;
208+
}
209+
abort();
210+
}

reftable/basics.h

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ license that can be found in the LICENSE file or at
1414
*/
1515

1616
#include "system.h"
17+
#include "reftable-basics.h"
1718

1819
/* Bigendian en/decoding of integers */
1920

@@ -37,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
3738
*/
3839
void free_names(char **a);
3940

40-
/* parse a newline separated list of names. `size` is the length of the buffer,
41-
* without terminating '\0'. Empty names are discarded. */
42-
void parse_names(char *buf, int size, char ***namesp);
41+
/*
42+
* Parse a newline separated list of names. `size` is the length of the buffer,
43+
* without terminating '\0'. Empty names are discarded. Returns a `NULL`
44+
* pointer when allocations fail.
45+
*/
46+
char **parse_names(char *buf, int size);
4347

4448
/* compares two NULL-terminated arrays of strings. */
4549
int names_equal(const char **a, const char **b);
@@ -53,6 +57,7 @@ void *reftable_malloc(size_t sz);
5357
void *reftable_realloc(void *p, size_t sz);
5458
void reftable_free(void *p);
5559
void *reftable_calloc(size_t nelem, size_t elsize);
60+
char *reftable_strdup(const char *str);
5661

5762
#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
5863
#define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
@@ -66,9 +71,26 @@ void *reftable_calloc(size_t nelem, size_t elsize);
6671
REFTABLE_REALLOC_ARRAY(x, alloc); \
6772
} \
6873
} while (0)
74+
#define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0)
75+
76+
#ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS
77+
# define REFTABLE_BANNED(func) use_reftable_##func##_instead
78+
# undef malloc
79+
# define malloc(sz) REFTABLE_BANNED(malloc)
80+
# undef realloc
81+
# define realloc(ptr, sz) REFTABLE_BANNED(realloc)
82+
# undef free
83+
# define free(ptr) REFTABLE_BANNED(free)
84+
# undef calloc
85+
# define calloc(nelem, elsize) REFTABLE_BANNED(calloc)
86+
# undef strdup
87+
# define strdup(str) REFTABLE_BANNED(strdup)
88+
#endif
6989

7090
/* Find the longest shared prefix size of `a` and `b` */
7191
struct strbuf;
7292
int common_prefix_size(struct strbuf *a, struct strbuf *b);
7393

94+
int hash_size(uint32_t id);
95+
7496
#endif

reftable/block.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
5252
return -1;
5353
if (is_restart) {
5454
REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap);
55+
if (!w->restarts)
56+
return REFTABLE_OUT_OF_MEMORY_ERROR;
5557
w->restarts[w->restart_len++] = w->next;
5658
}
5759

@@ -63,8 +65,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
6365
return 0;
6466
}
6567

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)
6870
{
6971
bw->buf = buf;
7072
bw->hash_size = hash_size;
@@ -78,8 +80,12 @@ void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
7880
bw->last_key.len = 0;
7981
if (!bw->zstream) {
8082
REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
83+
if (!bw->zstream)
84+
return REFTABLE_OUT_OF_MEMORY_ERROR;
8185
deflateInit(bw->zstream, 9);
8286
}
87+
88+
return 0;
8389
}
8490

8591
uint8_t block_writer_type(struct block_writer *bw)
@@ -163,6 +169,10 @@ int block_writer_finish(struct block_writer *w)
163169
*/
164170
compressed_len = deflateBound(w->zstream, src_len);
165171
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+
}
166176

167177
w->zstream->next_out = w->compressed;
168178
w->zstream->avail_out = compressed_len;
@@ -219,12 +229,21 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
219229
/* Log blocks specify the *uncompressed* size in their header. */
220230
REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
221231
br->uncompressed_cap);
232+
if (!br->uncompressed_data) {
233+
err = REFTABLE_OUT_OF_MEMORY_ERROR;
234+
goto done;
235+
}
222236

223237
/* Copy over the block header verbatim. It's not compressed. */
224238
memcpy(br->uncompressed_data, block->data, block_header_skip);
225239

226240
if (!br->zstream) {
227241
REFTABLE_CALLOC_ARRAY(br->zstream, 1);
242+
if (!br->zstream) {
243+
err = REFTABLE_OUT_OF_MEMORY_ERROR;
244+
goto done;
245+
}
246+
228247
err = inflateInit(br->zstream);
229248
} else {
230249
err = inflateReset(br->zstream);
@@ -532,9 +551,9 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
532551
void block_writer_release(struct block_writer *bw)
533552
{
534553
deflateEnd(bw->zstream);
535-
FREE_AND_NULL(bw->zstream);
536-
FREE_AND_NULL(bw->restarts);
537-
FREE_AND_NULL(bw->compressed);
554+
REFTABLE_FREE_AND_NULL(bw->zstream);
555+
REFTABLE_FREE_AND_NULL(bw->restarts);
556+
REFTABLE_FREE_AND_NULL(bw->compressed);
538557
strbuf_release(&bw->last_key);
539558
/* the block is not owned. */
540559
}

0 commit comments

Comments
 (0)