summaryrefslogtreecommitdiffstats
path: root/reftable
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2024-10-10 23:22:24 +0200
committerJunio C Hamano <gitster@pobox.com>2024-10-10 23:22:25 +0200
commit5575c713c2a398f4723c544fb732c44b8e1d5e45 (patch)
tree05f7f70eaf278c2bf07498a6d5807915bc3d40e4 /reftable
parentMerge branch 'ja/doc-synopsis-markup' (diff)
parentreftable/basics: fix segfault when growing `names` array fails (diff)
downloadgit-5575c713c2a398f4723c544fb732c44b8e1d5e45.tar.xz
git-5575c713c2a398f4723c544fb732c44b8e1d5e45.zip
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 ...
Diffstat (limited to 'reftable')
-rw-r--r--reftable/basics.c97
-rw-r--r--reftable/basics.h28
-rw-r--r--reftable/block.c29
-rw-r--r--reftable/block.h4
-rw-r--r--reftable/blocksource.c25
-rw-r--r--reftable/error.c2
-rw-r--r--reftable/iter.c22
-rw-r--r--reftable/iter.h2
-rw-r--r--reftable/merged.c84
-rw-r--r--reftable/merged.h6
-rw-r--r--reftable/pq.c9
-rw-r--r--reftable/pq.h2
-rw-r--r--reftable/publicbasics.c66
-rw-r--r--reftable/reader.c70
-rw-r--r--reftable/reader.h6
-rw-r--r--reftable/record.c174
-rw-r--r--reftable/record.h6
-rw-r--r--reftable/reftable-basics.h18
-rw-r--r--reftable/reftable-error.h3
-rw-r--r--reftable/reftable-malloc.h18
-rw-r--r--reftable/reftable-merged.h8
-rw-r--r--reftable/reftable-reader.h8
-rw-r--r--reftable/reftable-stack.h8
-rw-r--r--reftable/reftable-writer.h12
-rw-r--r--reftable/stack.c187
-rw-r--r--reftable/tree.c42
-rw-r--r--reftable/tree.h21
-rw-r--r--reftable/writer.c154
28 files changed, 765 insertions, 346 deletions
diff --git a/reftable/basics.c b/reftable/basics.c
index 0058619ca6..9a949e5cf8 100644
--- a/reftable/basics.c
+++ b/reftable/basics.c
@@ -6,7 +6,68 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#define REFTABLE_ALLOW_BANNED_ALLOCATORS
#include "basics.h"
+#include "reftable-basics.h"
+
+static void *(*reftable_malloc_ptr)(size_t sz);
+static void *(*reftable_realloc_ptr)(void *, size_t);
+static void (*reftable_free_ptr)(void *);
+
+void *reftable_malloc(size_t sz)
+{
+ if (reftable_malloc_ptr)
+ return (*reftable_malloc_ptr)(sz);
+ return malloc(sz);
+}
+
+void *reftable_realloc(void *p, size_t sz)
+{
+ if (reftable_realloc_ptr)
+ return (*reftable_realloc_ptr)(p, sz);
+ return realloc(p, sz);
+}
+
+void reftable_free(void *p)
+{
+ if (reftable_free_ptr)
+ reftable_free_ptr(p);
+ else
+ free(p);
+}
+
+void *reftable_calloc(size_t nelem, size_t elsize)
+{
+ void *p;
+
+ if (nelem && elsize > SIZE_MAX / nelem)
+ return NULL;
+
+ p = reftable_malloc(nelem * elsize);
+ if (!p)
+ return NULL;
+
+ memset(p, 0, nelem * elsize);
+ return p;
+}
+
+char *reftable_strdup(const char *str)
+{
+ size_t len = strlen(str);
+ char *result = reftable_malloc(len + 1);
+ if (!result)
+ return NULL;
+ memcpy(result, str, len + 1);
+ return result;
+}
+
+void reftable_set_alloc(void *(*malloc)(size_t),
+ void *(*realloc)(void *, size_t), void (*free)(void *))
+{
+ reftable_malloc_ptr = malloc;
+ reftable_realloc_ptr = realloc;
+ reftable_free_ptr = free;
+}
void put_be24(uint8_t *out, uint32_t i)
{
@@ -75,14 +136,14 @@ size_t names_length(const char **names)
return p - names;
}
-void parse_names(char *buf, int size, char ***namesp)
+char **parse_names(char *buf, int size)
{
char **names = NULL;
size_t names_cap = 0;
size_t names_len = 0;
-
char *p = buf;
char *end = buf + size;
+
while (p < end) {
char *next = strchr(p, '\n');
if (next && next < end) {
@@ -91,15 +152,29 @@ void parse_names(char *buf, int size, char ***namesp)
next = end;
}
if (p < next) {
- REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap);
- names[names_len++] = xstrdup(p);
+ char **names_grown = names;
+ REFTABLE_ALLOC_GROW(names_grown, names_len + 1, names_cap);
+ if (!names_grown)
+ goto err;
+ names = names_grown;
+
+ names[names_len] = reftable_strdup(p);
+ if (!names[names_len++])
+ goto err;
}
p = next + 1;
}
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
names[names_len] = NULL;
- *namesp = names;
+
+ return names;
+
+err:
+ for (size_t i = 0; i < names_len; i++)
+ reftable_free(names[i]);
+ reftable_free(names);
+ return NULL;
}
int names_equal(const char **a, const char **b)
@@ -121,3 +196,15 @@ int common_prefix_size(struct strbuf *a, struct strbuf *b)
return p;
}
+
+int hash_size(uint32_t id)
+{
+ switch (id) {
+ case 0:
+ case GIT_SHA1_FORMAT_ID:
+ return GIT_SHA1_RAWSZ;
+ case GIT_SHA256_FORMAT_ID:
+ return GIT_SHA256_RAWSZ;
+ }
+ abort();
+}
diff --git a/reftable/basics.h b/reftable/basics.h
index c8fec68d4e..4c9ef0fe6c 100644
--- a/reftable/basics.h
+++ b/reftable/basics.h
@@ -14,6 +14,7 @@ https://developers.google.com/open-source/licenses/bsd
*/
#include "system.h"
+#include "reftable-basics.h"
/* Bigendian en/decoding of integers */
@@ -37,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
*/
void free_names(char **a);
-/* parse a newline separated list of names. `size` is the length of the buffer,
- * without terminating '\0'. Empty names are discarded. */
-void parse_names(char *buf, int size, char ***namesp);
+/*
+ * Parse a newline separated list of names. `size` is the length of the buffer,
+ * without terminating '\0'. Empty names are discarded. Returns a `NULL`
+ * pointer when allocations fail.
+ */
+char **parse_names(char *buf, int size);
/* compares two NULL-terminated arrays of strings. */
int names_equal(const char **a, const char **b);
@@ -53,6 +57,7 @@ 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);
+char *reftable_strdup(const char *str);
#define REFTABLE_ALLOC_ARRAY(x, alloc) (x) = reftable_malloc(st_mult(sizeof(*(x)), (alloc)))
#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);
REFTABLE_REALLOC_ARRAY(x, alloc); \
} \
} while (0)
+#define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0)
+
+#ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS
+# define REFTABLE_BANNED(func) use_reftable_##func##_instead
+# undef malloc
+# define malloc(sz) REFTABLE_BANNED(malloc)
+# undef realloc
+# define realloc(ptr, sz) REFTABLE_BANNED(realloc)
+# undef free
+# define free(ptr) REFTABLE_BANNED(free)
+# undef calloc
+# define calloc(nelem, elsize) REFTABLE_BANNED(calloc)
+# undef strdup
+# define strdup(str) REFTABLE_BANNED(strdup)
+#endif
/* Find the longest shared prefix size of `a` and `b` */
struct strbuf;
int common_prefix_size(struct strbuf *a, struct strbuf *b);
+int hash_size(uint32_t id);
+
#endif
diff --git a/reftable/block.c b/reftable/block.c
index 00030eee06..8d41a2f99e 100644
--- a/reftable/block.c
+++ b/reftable/block.c
@@ -52,6 +52,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
return -1;
if (is_restart) {
REFTABLE_ALLOC_GROW(w->restarts, w->restart_len + 1, w->restart_cap);
+ if (!w->restarts)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
w->restarts[w->restart_len++] = w->next;
}
@@ -63,8 +65,8 @@ static int block_writer_register_restart(struct block_writer *w, int n,
return 0;
}
-void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
- uint32_t block_size, uint32_t header_off, int hash_size)
+int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
+ uint32_t block_size, uint32_t header_off, int hash_size)
{
bw->buf = buf;
bw->hash_size = hash_size;
@@ -78,8 +80,12 @@ void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
bw->last_key.len = 0;
if (!bw->zstream) {
REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
+ if (!bw->zstream)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
deflateInit(bw->zstream, 9);
}
+
+ return 0;
}
uint8_t block_writer_type(struct block_writer *bw)
@@ -163,6 +169,10 @@ int block_writer_finish(struct block_writer *w)
*/
compressed_len = deflateBound(w->zstream, src_len);
REFTABLE_ALLOC_GROW(w->compressed, compressed_len, w->compressed_cap);
+ if (!w->compressed) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ return ret;
+ }
w->zstream->next_out = w->compressed;
w->zstream->avail_out = compressed_len;
@@ -219,12 +229,21 @@ int block_reader_init(struct block_reader *br, struct reftable_block *block,
/* Log blocks specify the *uncompressed* size in their header. */
REFTABLE_ALLOC_GROW(br->uncompressed_data, sz,
br->uncompressed_cap);
+ if (!br->uncompressed_data) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
/* Copy over the block header verbatim. It's not compressed. */
memcpy(br->uncompressed_data, block->data, block_header_skip);
if (!br->zstream) {
REFTABLE_CALLOC_ARRAY(br->zstream, 1);
+ if (!br->zstream) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
err = inflateInit(br->zstream);
} else {
err = inflateReset(br->zstream);
@@ -532,9 +551,9 @@ done:
void block_writer_release(struct block_writer *bw)
{
deflateEnd(bw->zstream);
- FREE_AND_NULL(bw->zstream);
- FREE_AND_NULL(bw->restarts);
- FREE_AND_NULL(bw->compressed);
+ REFTABLE_FREE_AND_NULL(bw->zstream);
+ REFTABLE_FREE_AND_NULL(bw->restarts);
+ REFTABLE_FREE_AND_NULL(bw->compressed);
strbuf_release(&bw->last_key);
/* the block is not owned. */
}
diff --git a/reftable/block.h b/reftable/block.h
index 1c8f25ee6e..18d7ea0337 100644
--- a/reftable/block.h
+++ b/reftable/block.h
@@ -45,8 +45,8 @@ struct block_writer {
/*
* initializes the blockwriter to write `typ` entries, using `buf` as temporary
* storage. `buf` is not owned by the block_writer. */
-void block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
- uint32_t block_size, uint32_t header_off, int hash_size);
+int block_writer_init(struct block_writer *bw, uint8_t typ, uint8_t *buf,
+ uint32_t block_size, uint32_t header_off, int hash_size);
/* returns the block type (eg. 'r' for ref records. */
uint8_t block_writer_type(struct block_writer *bw);
diff --git a/reftable/blocksource.c b/reftable/blocksource.c
index e93cac9bb6..a2a6a196d5 100644
--- a/reftable/blocksource.c
+++ b/reftable/blocksource.c
@@ -30,6 +30,8 @@ static int strbuf_read_block(void *v, struct reftable_block *dest, uint64_t off,
struct strbuf *b = v;
assert(off + size <= b->len);
REFTABLE_CALLOC_ARRAY(dest->data, size);
+ if (!dest->data)
+ return -1;
memcpy(dest->data, b->buf + off, size);
dest->len = size;
return size;
@@ -98,27 +100,40 @@ int reftable_block_source_from_file(struct reftable_block_source *bs,
{
struct file_block_source *p;
struct stat st;
- int fd;
+ int fd, err;
fd = open(name, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
return REFTABLE_NOT_EXIST_ERROR;
- return -1;
+ err = -1;
+ goto out;
}
if (fstat(fd, &st) < 0) {
- close(fd);
- return REFTABLE_IO_ERROR;
+ err = REFTABLE_IO_ERROR;
+ goto out;
}
REFTABLE_CALLOC_ARRAY(p, 1);
+ if (!p) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
p->size = st.st_size;
p->data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- close(fd);
assert(!bs->ops);
bs->ops = &file_vtable;
bs->arg = p;
+
+ err = 0;
+
+out:
+ if (fd >= 0)
+ close(fd);
+ if (err < 0)
+ reftable_free(p);
return 0;
}
diff --git a/reftable/error.c b/reftable/error.c
index a25f28a43e..660d029617 100644
--- a/reftable/error.c
+++ b/reftable/error.c
@@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
return "entry too large";
case REFTABLE_OUTDATED_ERROR:
return "data concurrently modified";
+ case REFTABLE_OUT_OF_MEMORY_ERROR:
+ return "out of memory";
case -1:
return "general error";
default:
diff --git a/reftable/iter.c b/reftable/iter.c
index 416a9f6996..d926db653b 100644
--- a/reftable/iter.c
+++ b/reftable/iter.c
@@ -181,14 +181,20 @@ static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
}
}
-int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
+int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len)
{
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
- struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
+ struct indexed_table_ref_iter *itr;
int err = 0;
+ itr = reftable_calloc(1, sizeof(*itr));
+ if (!itr) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
*itr = empty;
itr->r = r;
strbuf_add(&itr->oid, oid, oid_len);
@@ -197,10 +203,16 @@ int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
itr->offset_len = offset_len;
err = indexed_table_ref_iter_next_block(itr);
+ if (err < 0)
+ goto out;
+
+ *dest = itr;
+ err = 0;
+
+out:
if (err < 0) {
+ *dest = NULL;
reftable_free(itr);
- } else {
- *dest = itr;
}
return err;
}
@@ -225,7 +237,7 @@ void reftable_iterator_destroy(struct reftable_iterator *it)
return;
it->ops->close(it->iter_arg);
it->ops = NULL;
- FREE_AND_NULL(it->iter_arg);
+ REFTABLE_FREE_AND_NULL(it->iter_arg);
}
int reftable_iterator_seek_ref(struct reftable_iterator *it,
diff --git a/reftable/iter.h b/reftable/iter.h
index befc4597df..b3225bc7ad 100644
--- a/reftable/iter.h
+++ b/reftable/iter.h
@@ -82,7 +82,7 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
struct indexed_table_ref_iter *itr);
/* Takes ownership of `offsets` */
-int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
+int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len);
diff --git a/reftable/merged.c b/reftable/merged.c
index 128a810c55..514d6facf4 100644
--- a/reftable/merged.c
+++ b/reftable/merged.c
@@ -30,22 +30,6 @@ struct merged_iter {
ssize_t advance_index;
};
-static void merged_iter_init(struct merged_iter *mi,
- struct reftable_merged_table *mt,
- uint8_t typ)
-{
- memset(mi, 0, sizeof(*mi));
- mi->advance_index = -1;
- mi->suppress_deletions = mt->suppress_deletions;
-
- REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
- for (size_t i = 0; i < mt->readers_len; i++) {
- reftable_record_init(&mi->subiters[i].rec, typ);
- reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
- }
- mi->subiters_len = mt->readers_len;
-}
-
static void merged_iter_close(void *p)
{
struct merged_iter *mi = p;
@@ -70,7 +54,10 @@ static int merged_iter_advance_subiter(struct merged_iter *mi, size_t idx)
if (err)
return err;
- merged_iter_pqueue_add(&mi->pq, &e);
+ err = merged_iter_pqueue_add(&mi->pq, &e);
+ if (err)
+ return err;
+
return 0;
}
@@ -216,6 +203,9 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
}
REFTABLE_CALLOC_ARRAY(m, 1);
+ if (!m)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
m->readers = readers;
m->readers_len = n;
m->min = first_min;
@@ -244,25 +234,63 @@ reftable_merged_table_min_update_index(struct reftable_merged_table *mt)
return mt->min;
}
-void merged_table_init_iter(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- uint8_t typ)
+int merged_table_init_iter(struct reftable_merged_table *mt,
+ struct reftable_iterator *it,
+ uint8_t typ)
{
- struct merged_iter *mi = reftable_malloc(sizeof(*mi));
- merged_iter_init(mi, mt, typ);
+ struct merged_subiter *subiters;
+ struct merged_iter *mi = NULL;
+ int ret;
+
+ REFTABLE_CALLOC_ARRAY(subiters, mt->readers_len);
+ if (!subiters) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
+ for (size_t i = 0; i < mt->readers_len; i++) {
+ reftable_record_init(&subiters[i].rec, typ);
+ ret = reader_init_iter(mt->readers[i], &subiters[i].iter, typ);
+ if (ret < 0)
+ goto out;
+ }
+
+ REFTABLE_CALLOC_ARRAY(mi, 1);
+ if (!mi) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+ mi->advance_index = -1;
+ mi->suppress_deletions = mt->suppress_deletions;
+ mi->subiters = subiters;
+ mi->subiters_len = mt->readers_len;
+
iterator_from_merged_iter(it, mi);
+ ret = 0;
+
+out:
+ if (ret < 0) {
+ for (size_t i = 0; subiters && i < mt->readers_len; i++) {
+ reftable_iterator_destroy(&subiters[i].iter);
+ reftable_record_release(&subiters[i].rec);
+ }
+ reftable_free(subiters);
+ reftable_free(mi);
+ }
+
+ return ret;
}
-void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
- struct reftable_iterator *it)
+int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it)
{
- merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
+ return merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
}
-void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
- struct reftable_iterator *it)
+int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it)
{
- merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
+ return merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
}
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
diff --git a/reftable/merged.h b/reftable/merged.h
index de5fd33f01..89bd0c4b35 100644
--- a/reftable/merged.h
+++ b/reftable/merged.h
@@ -26,8 +26,8 @@ struct reftable_merged_table {
struct reftable_iterator;
-void merged_table_init_iter(struct reftable_merged_table *mt,
- struct reftable_iterator *it,
- uint8_t typ);
+int merged_table_init_iter(struct reftable_merged_table *mt,
+ struct reftable_iterator *it,
+ uint8_t typ);
#endif
diff --git a/reftable/pq.c b/reftable/pq.c
index 2b5b7d1c0e..6ee1164dd3 100644
--- a/reftable/pq.c
+++ b/reftable/pq.c
@@ -8,6 +8,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "pq.h"
+#include "reftable-error.h"
#include "reftable-record.h"
#include "system.h"
#include "basics.h"
@@ -44,11 +45,13 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
return e;
}
-void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
+int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
{
size_t i = 0;
REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap);
+ if (!pq->heap)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
pq->heap[pq->len++] = *e;
i = pq->len - 1;
@@ -59,10 +62,12 @@ void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry
SWAP(pq->heap[j], pq->heap[i]);
i = j;
}
+
+ return 0;
}
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq)
{
- FREE_AND_NULL(pq->heap);
+ REFTABLE_FREE_AND_NULL(pq->heap);
memset(pq, 0, sizeof(*pq));
}
diff --git a/reftable/pq.h b/reftable/pq.h
index 707bd26767..83c062eeca 100644
--- a/reftable/pq.h
+++ b/reftable/pq.h
@@ -23,7 +23,7 @@ struct merged_iter_pqueue {
};
struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
-void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
+int merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
int pq_less(struct pq_entry *a, struct pq_entry *b);
diff --git a/reftable/publicbasics.c b/reftable/publicbasics.c
deleted file mode 100644
index 44b84a125e..0000000000
--- a/reftable/publicbasics.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#include "system.h"
-#include "reftable-malloc.h"
-
-#include "basics.h"
-
-static void *(*reftable_malloc_ptr)(size_t sz);
-static void *(*reftable_realloc_ptr)(void *, size_t);
-static void (*reftable_free_ptr)(void *);
-
-void *reftable_malloc(size_t sz)
-{
- if (reftable_malloc_ptr)
- return (*reftable_malloc_ptr)(sz);
- return malloc(sz);
-}
-
-void *reftable_realloc(void *p, size_t sz)
-{
- if (reftable_realloc_ptr)
- return (*reftable_realloc_ptr)(p, sz);
- return realloc(p, sz);
-}
-
-void reftable_free(void *p)
-{
- if (reftable_free_ptr)
- reftable_free_ptr(p);
- else
- free(p);
-}
-
-void *reftable_calloc(size_t nelem, size_t elsize)
-{
- size_t sz = st_mult(nelem, elsize);
- void *p = reftable_malloc(sz);
- memset(p, 0, sz);
- return p;
-}
-
-void reftable_set_alloc(void *(*malloc)(size_t),
- void *(*realloc)(void *, size_t), void (*free)(void *))
-{
- reftable_malloc_ptr = malloc;
- reftable_realloc_ptr = realloc;
- reftable_free_ptr = free;
-}
-
-int hash_size(uint32_t id)
-{
- switch (id) {
- case 0:
- case GIT_SHA1_FORMAT_ID:
- return GIT_SHA1_RAWSZ;
- case GIT_SHA256_FORMAT_ID:
- return GIT_SHA256_RAWSZ;
- }
- abort();
-}
diff --git a/reftable/reader.c b/reftable/reader.c
index 6494ce2e32..8d37253922 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -554,32 +554,37 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
it->ops = &table_iter_vtable;
}
-void reader_init_iter(struct reftable_reader *r,
- struct reftable_iterator *it,
- uint8_t typ)
+int reader_init_iter(struct reftable_reader *r,
+ struct reftable_iterator *it,
+ uint8_t typ)
{
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
if (offs->is_present) {
struct table_iter *ti;
REFTABLE_ALLOC_ARRAY(ti, 1);
+ if (!ti)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
table_iter_init(ti, r);
iterator_from_table_iter(it, ti);
} else {
iterator_set_empty(it);
}
+
+ return 0;
}
-void reftable_reader_init_ref_iterator(struct reftable_reader *r,
- struct reftable_iterator *it)
+int reftable_reader_init_ref_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it)
{
- reader_init_iter(r, it, BLOCK_TYPE_REF);
+ return reader_init_iter(r, it, BLOCK_TYPE_REF);
}
-void reftable_reader_init_log_iterator(struct reftable_reader *r,
- struct reftable_iterator *it)
+int reftable_reader_init_log_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it)
{
- reader_init_iter(r, it, BLOCK_TYPE_LOG);
+ return reader_init_iter(r, it, BLOCK_TYPE_LOG);
}
int reftable_reader_new(struct reftable_reader **out,
@@ -593,6 +598,10 @@ int reftable_reader_new(struct reftable_reader **out,
int err;
REFTABLE_CALLOC_ARRAY(r, 1);
+ if (!r) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
/*
* We need one extra byte to read the type of first block. We also
@@ -622,7 +631,11 @@ int reftable_reader_new(struct reftable_reader **out,
r->size = file_size - footer_size(r->version);
r->source = *source;
- r->name = xstrdup(name);
+ r->name = reftable_strdup(name);
+ if (!r->name) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
r->hash_id = 0;
r->refcount = 1;
@@ -665,7 +678,7 @@ void reftable_reader_decref(struct reftable_reader *r)
if (--r->refcount)
return;
block_source_close(&r->source);
- FREE_AND_NULL(r->name);
+ REFTABLE_FREE_AND_NULL(r->name);
reftable_free(r);
}
@@ -689,7 +702,10 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
struct indexed_table_ref_iter *itr = NULL;
/* Look through the reverse index. */
- reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
+ err = reader_init_iter(r, &oit, BLOCK_TYPE_OBJ);
+ if (err < 0)
+ goto done;
+
err = iterator_seek(&oit, &want);
if (err != 0)
goto done;
@@ -707,7 +723,7 @@ static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
goto done;
}
- err = new_indexed_table_ref_iter(&itr, r, oid, hash_size(r->hash_id),
+ err = indexed_table_ref_iter_new(&itr, r, oid, hash_size(r->hash_id),
got.u.obj.offsets,
got.u.obj.offset_len);
if (err < 0)
@@ -732,21 +748,37 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
int err;
REFTABLE_ALLOC_ARRAY(ti, 1);
+ if (!ti) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
table_iter_init(ti, r);
err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
- if (err < 0) {
- reftable_free(ti);
- return err;
- }
+ if (err < 0)
+ goto out;
- filter = reftable_malloc(sizeof(struct filtering_ref_iterator));
+ filter = reftable_malloc(sizeof(*filter));
+ if (!filter) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
*filter = empty;
strbuf_add(&filter->oid, oid, oid_len);
iterator_from_table_iter(&filter->it, ti);
iterator_from_filtering_ref_iterator(it, filter);
- return 0;
+
+ err = 0;
+
+out:
+ if (err < 0) {
+ if (ti)
+ table_iter_close(ti);
+ reftable_free(ti);
+ }
+ return err;
}
int reftable_reader_refs_for(struct reftable_reader *r,
diff --git a/reftable/reader.h b/reftable/reader.h
index 91377b9ce5..010fbfe851 100644
--- a/reftable/reader.h
+++ b/reftable/reader.h
@@ -56,9 +56,9 @@ struct reftable_reader {
const char *reader_name(struct reftable_reader *r);
-void reader_init_iter(struct reftable_reader *r,
- struct reftable_iterator *it,
- uint8_t typ);
+int reader_init_iter(struct reftable_reader *r,
+ struct reftable_iterator *it,
+ uint8_t typ);
/* initialize a block reader to read from `r` */
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
diff --git a/reftable/record.c b/reftable/record.c
index 6b5a075b92..30d563e16d 100644
--- a/reftable/record.c
+++ b/reftable/record.c
@@ -215,13 +215,14 @@ static void reftable_ref_record_key(const void *r, struct strbuf *dest)
strbuf_addstr(dest, rec->refname);
}
-static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
- int hash_size)
+static int reftable_ref_record_copy_from(void *rec, const void *src_rec,
+ int hash_size)
{
struct reftable_ref_record *ref = rec;
const struct reftable_ref_record *src = src_rec;
char *refname = NULL;
size_t refname_cap = 0;
+ int err;
assert(hash_size > 0);
@@ -236,6 +237,11 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
REFTABLE_ALLOC_GROW(ref->refname, refname_len + 1,
ref->refname_cap);
+ if (!ref->refname) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
+
memcpy(ref->refname, src->refname, refname_len);
ref->refname[refname_len] = 0;
}
@@ -254,9 +260,17 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
src->value.val2.target_value, hash_size);
break;
case REFTABLE_REF_SYMREF:
- ref->value.symref = xstrdup(src->value.symref);
+ ref->value.symref = reftable_strdup(src->value.symref);
+ if (!ref->value.symref) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
break;
}
+
+ err = 0;
+out:
+ return err;
}
static void reftable_ref_record_release_void(void *rec)
@@ -345,7 +359,7 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
uint64_t update_index = 0;
const char *refname = NULL;
size_t refname_cap = 0;
- int n;
+ int n, err;
assert(hash_size > 0);
@@ -361,6 +375,10 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
SWAP(r->refname_cap, refname_cap);
REFTABLE_ALLOC_GROW(r->refname, key.len + 1, r->refname_cap);
+ if (!r->refname) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
memcpy(r->refname, key.buf, key.len);
r->refname[key.len] = 0;
@@ -369,7 +387,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
switch (val_type) {
case REFTABLE_REF_VAL1:
if (in.len < hash_size) {
- return -1;
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
}
memcpy(r->value.val1, in.buf, hash_size);
@@ -378,7 +397,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
case REFTABLE_REF_VAL2:
if (in.len < 2 * hash_size) {
- return -1;
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
}
memcpy(r->value.val2.value, in.buf, hash_size);
@@ -391,7 +411,8 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
case REFTABLE_REF_SYMREF: {
int n = decode_string(scratch, in);
if (n < 0) {
- return -1;
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
}
string_view_consume(&in, n);
r->value.symref = strbuf_detach(scratch, NULL);
@@ -405,6 +426,9 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
}
return start.len - in.len;
+
+done:
+ return err;
}
static int reftable_ref_record_is_deletion_void(const void *p)
@@ -452,28 +476,33 @@ static void reftable_obj_record_key(const void *r, struct strbuf *dest)
static void reftable_obj_record_release(void *rec)
{
struct reftable_obj_record *obj = rec;
- FREE_AND_NULL(obj->hash_prefix);
- FREE_AND_NULL(obj->offsets);
+ REFTABLE_FREE_AND_NULL(obj->hash_prefix);
+ REFTABLE_FREE_AND_NULL(obj->offsets);
memset(obj, 0, sizeof(struct reftable_obj_record));
}
-static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
- int hash_size UNUSED)
+static int reftable_obj_record_copy_from(void *rec, const void *src_rec,
+ int hash_size UNUSED)
{
struct reftable_obj_record *obj = rec;
- const struct reftable_obj_record *src =
- (const struct reftable_obj_record *)src_rec;
+ const struct reftable_obj_record *src = src_rec;
reftable_obj_record_release(obj);
REFTABLE_ALLOC_ARRAY(obj->hash_prefix, src->hash_prefix_len);
+ if (!obj->hash_prefix)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->hash_prefix_len = src->hash_prefix_len;
if (src->hash_prefix_len)
memcpy(obj->hash_prefix, src->hash_prefix, obj->hash_prefix_len);
REFTABLE_ALLOC_ARRAY(obj->offsets, src->offset_len);
+ if (!obj->offsets)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
obj->offset_len = src->offset_len;
COPY_ARRAY(obj->offsets, src->offsets, src->offset_len);
+
+ return 0;
}
static uint8_t reftable_obj_record_val_type(const void *rec)
@@ -533,6 +562,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
reftable_obj_record_release(r);
REFTABLE_ALLOC_ARRAY(r->hash_prefix, key.len);
+ if (!r->hash_prefix)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
memcpy(r->hash_prefix, key.buf, key.len);
r->hash_prefix_len = key.len;
@@ -551,6 +582,8 @@ static int reftable_obj_record_decode(void *rec, struct strbuf key,
return start.len - in.len;
REFTABLE_ALLOC_ARRAY(r->offsets, count);
+ if (!r->offsets)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
r->offset_len = count;
n = get_var_int(&r->offsets[0], &in);
@@ -646,33 +679,44 @@ static void reftable_log_record_key(const void *r, struct strbuf *dest)
strbuf_add(dest, i64, sizeof(i64));
}
-static void reftable_log_record_copy_from(void *rec, const void *src_rec,
- int hash_size)
+static int reftable_log_record_copy_from(void *rec, const void *src_rec,
+ int hash_size)
{
struct reftable_log_record *dst = rec;
const struct reftable_log_record *src =
(const struct reftable_log_record *)src_rec;
+ int ret;
reftable_log_record_release(dst);
*dst = *src;
+
if (dst->refname) {
- dst->refname = xstrdup(dst->refname);
+ dst->refname = reftable_strdup(dst->refname);
+ if (!dst->refname) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
}
+
switch (dst->value_type) {
case REFTABLE_LOG_DELETION:
break;
case REFTABLE_LOG_UPDATE:
- if (dst->value.update.email) {
+ if (dst->value.update.email)
dst->value.update.email =
- xstrdup(dst->value.update.email);
- }
- if (dst->value.update.name) {
+ reftable_strdup(dst->value.update.email);
+ if (dst->value.update.name)
dst->value.update.name =
- xstrdup(dst->value.update.name);
- }
- if (dst->value.update.message) {
+ reftable_strdup(dst->value.update.name);
+ if (dst->value.update.message)
dst->value.update.message =
- xstrdup(dst->value.update.message);
+ reftable_strdup(dst->value.update.message);
+
+ if (!dst->value.update.email ||
+ !dst->value.update.name ||
+ !dst->value.update.message) {
+ ret = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
}
memcpy(dst->value.update.new_hash,
@@ -681,6 +725,10 @@ static void reftable_log_record_copy_from(void *rec, const void *src_rec,
src->value.update.old_hash, hash_size);
break;
}
+
+ ret = 0;
+out:
+ return ret;
}
static void reftable_log_record_release_void(void *rec)
@@ -767,12 +815,17 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
struct reftable_log_record *r = rec;
uint64_t max = 0;
uint64_t ts = 0;
- int n;
+ int err, n;
if (key.len <= 9 || key.buf[key.len - 9] != 0)
return REFTABLE_FORMAT_ERROR;
REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap);
+ if (!r->refname) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
memcpy(r->refname, key.buf, key.len - 8);
ts = get_be64(key.buf + key.len - 8);
@@ -781,10 +834,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type != r->value_type) {
switch (r->value_type) {
case REFTABLE_LOG_UPDATE:
- FREE_AND_NULL(r->value.update.message);
+ REFTABLE_FREE_AND_NULL(r->value.update.message);
r->value.update.message_cap = 0;
- FREE_AND_NULL(r->value.update.email);
- FREE_AND_NULL(r->value.update.name);
+ REFTABLE_FREE_AND_NULL(r->value.update.email);
+ REFTABLE_FREE_AND_NULL(r->value.update.name);
break;
case REFTABLE_LOG_DELETION:
break;
@@ -795,8 +848,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
if (val_type == REFTABLE_LOG_DELETION)
return 0;
- if (in.len < 2 * hash_size)
- return REFTABLE_FORMAT_ERROR;
+ if (in.len < 2 * hash_size) {
+ err = REFTABLE_FORMAT_ERROR;
+ goto done;
+ }
memcpy(r->value.update.old_hash, in.buf, hash_size);
memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
@@ -804,8 +859,10 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
string_view_consume(&in, 2 * hash_size);
n = decode_string(scratch, in);
- if (n < 0)
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
/*
@@ -816,52 +873,75 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
*/
if (!r->value.update.name ||
strcmp(r->value.update.name, scratch->buf)) {
- r->value.update.name =
- reftable_realloc(r->value.update.name, scratch->len + 1);
+ char *name = reftable_realloc(r->value.update.name, scratch->len + 1);
+ if (!name) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ r->value.update.name = name;
memcpy(r->value.update.name, scratch->buf, scratch->len);
r->value.update.name[scratch->len] = 0;
}
n = decode_string(scratch, in);
- if (n < 0)
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
/* Same as above, but for the reflog email. */
if (!r->value.update.email ||
strcmp(r->value.update.email, scratch->buf)) {
- r->value.update.email =
- reftable_realloc(r->value.update.email, scratch->len + 1);
+ char *email = reftable_realloc(r->value.update.email, scratch->len + 1);
+ if (!email) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ r->value.update.email = email;
memcpy(r->value.update.email, scratch->buf, scratch->len);
r->value.update.email[scratch->len] = 0;
}
ts = 0;
n = get_var_int(&ts, &in);
- if (n < 0)
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
r->value.update.time = ts;
- if (in.len < 2)
+ if (in.len < 2) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
r->value.update.tz_offset = get_be16(in.buf);
string_view_consume(&in, 2);
n = decode_string(scratch, in);
- if (n < 0)
+ if (n < 0) {
+ err = REFTABLE_FORMAT_ERROR;
goto done;
+ }
string_view_consume(&in, n);
REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
r->value.update.message_cap);
+ if (!r->value.update.message) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
memcpy(r->value.update.message, scratch->buf, scratch->len);
r->value.update.message[scratch->len] = 0;
return start.len - in.len;
done:
- return REFTABLE_FORMAT_ERROR;
+ return err;
}
static int null_streq(const char *a, const char *b)
@@ -954,8 +1034,8 @@ static void reftable_index_record_key(const void *r, struct strbuf *dest)
strbuf_addbuf(dest, &rec->last_key);
}
-static void reftable_index_record_copy_from(void *rec, const void *src_rec,
- int hash_size UNUSED)
+static int reftable_index_record_copy_from(void *rec, const void *src_rec,
+ int hash_size UNUSED)
{
struct reftable_index_record *dst = rec;
const struct reftable_index_record *src = src_rec;
@@ -963,6 +1043,8 @@ static void reftable_index_record_copy_from(void *rec, const void *src_rec,
strbuf_reset(&dst->last_key);
strbuf_addbuf(&dst->last_key, &src->last_key);
dst->offset = src->offset;
+
+ return 0;
}
static void reftable_index_record_release(void *rec)
@@ -1054,14 +1136,14 @@ int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
dest, hash_size);
}
-void reftable_record_copy_from(struct reftable_record *rec,
+int reftable_record_copy_from(struct reftable_record *rec,
struct reftable_record *src, int hash_size)
{
assert(src->type == rec->type);
- reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
- reftable_record_data(src),
- hash_size);
+ return reftable_record_vtable(rec)->copy_from(reftable_record_data(rec),
+ reftable_record_data(src),
+ hash_size);
}
uint8_t reftable_record_val_type(struct reftable_record *rec)
diff --git a/reftable/record.h b/reftable/record.h
index 5003bacdb0..0f53ba5443 100644
--- a/reftable/record.h
+++ b/reftable/record.h
@@ -44,7 +44,7 @@ struct reftable_record_vtable {
/* The record type of ('r' for ref). */
uint8_t type;
- void (*copy_from)(void *dest, const void *src, int hash_size);
+ int (*copy_from)(void *dest, const void *src, int hash_size);
/* a value of [0..7], indicating record subvariants (eg. ref vs. symref
* vs ref deletion) */
@@ -137,8 +137,8 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ);
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
-void reftable_record_copy_from(struct reftable_record *rec,
- struct reftable_record *src, int hash_size);
+int reftable_record_copy_from(struct reftable_record *rec,
+ struct reftable_record *src, int hash_size);
uint8_t reftable_record_val_type(struct reftable_record *rec);
int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
int hash_size);
diff --git a/reftable/reftable-basics.h b/reftable/reftable-basics.h
new file mode 100644
index 0000000000..6e8e636b71
--- /dev/null
+++ b/reftable/reftable-basics.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://developers.google.com/open-source/licenses/bsd
+*/
+
+#ifndef REFTABLE_BASICS_H
+#define REFTABLE_BASICS_H
+
+#include <stddef.h>
+
+/* Overrides the functions to use for memory management. */
+void reftable_set_alloc(void *(*malloc)(size_t),
+ void *(*realloc)(void *, size_t), void (*free)(void *));
+
+#endif
diff --git a/reftable/reftable-error.h b/reftable/reftable-error.h
index 6368cd9ed9..f404826562 100644
--- a/reftable/reftable-error.h
+++ b/reftable/reftable-error.h
@@ -57,6 +57,9 @@ enum reftable_error {
/* Trying to write out-of-date data. */
REFTABLE_OUTDATED_ERROR = -12,
+
+ /* An allocation has failed due to an out-of-memory situation. */
+ REFTABLE_OUT_OF_MEMORY_ERROR = -13,
};
/* convert the numeric error code to a string. The string should not be
diff --git a/reftable/reftable-malloc.h b/reftable/reftable-malloc.h
deleted file mode 100644
index 5f2185f1f3..0000000000
--- a/reftable/reftable-malloc.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2020 Google LLC
-
-Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file or at
-https://developers.google.com/open-source/licenses/bsd
-*/
-
-#ifndef REFTABLE_H
-#define REFTABLE_H
-
-#include <stddef.h>
-
-/* Overrides the functions to use for memory management. */
-void reftable_set_alloc(void *(*malloc)(size_t),
- void *(*realloc)(void *, size_t), void (*free)(void *));
-
-#endif
diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h
index 16d19f8df2..a970d5dd89 100644
--- a/reftable/reftable-merged.h
+++ b/reftable/reftable-merged.h
@@ -37,12 +37,12 @@ int reftable_merged_table_new(struct reftable_merged_table **dest,
uint32_t hash_id);
/* Initialize a merged table iterator for reading refs. */
-void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
- struct reftable_iterator *it);
+int reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it);
/* Initialize a merged table iterator for reading logs. */
-void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
- struct reftable_iterator *it);
+int reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
+ struct reftable_iterator *it);
/* returns the max update_index covered by this merged table. */
uint64_t
diff --git a/reftable/reftable-reader.h b/reftable/reftable-reader.h
index a600452b56..6a2d0b693f 100644
--- a/reftable/reftable-reader.h
+++ b/reftable/reftable-reader.h
@@ -46,12 +46,12 @@ void reftable_reader_incref(struct reftable_reader *reader);
void reftable_reader_decref(struct reftable_reader *reader);
/* Initialize a reftable iterator for reading refs. */
-void reftable_reader_init_ref_iterator(struct reftable_reader *r,
- struct reftable_iterator *it);
+int reftable_reader_init_ref_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it);
/* Initialize a reftable iterator for reading logs. */
-void reftable_reader_init_log_iterator(struct reftable_reader *r,
- struct reftable_iterator *it);
+int reftable_reader_init_log_iterator(struct reftable_reader *r,
+ struct reftable_iterator *it);
/* returns the hash ID used in this table. */
uint32_t reftable_reader_hash_id(struct reftable_reader *r);
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index 6370fe45dd..54787f2ef5 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -82,16 +82,16 @@ struct reftable_iterator;
* be used to iterate through refs. The iterator is valid until the next reload
* or write.
*/
-void reftable_stack_init_ref_iterator(struct reftable_stack *st,
- struct reftable_iterator *it);
+int reftable_stack_init_ref_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it);
/*
* Initialize an iterator for the merged tables contained in the stack that can
* be used to iterate through logs. The iterator is valid until the next reload
* or write.
*/
-void reftable_stack_init_log_iterator(struct reftable_stack *st,
- struct reftable_iterator *it);
+int reftable_stack_init_log_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it);
/* returns the merged_table for seeking. This table is valid until the
* next write or reload, and should not be closed or deleted.
diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h
index f5e25cfda1..e4fc953788 100644
--- a/reftable/reftable-writer.h
+++ b/reftable/reftable-writer.h
@@ -101,11 +101,13 @@ struct reftable_stats {
int object_id_len;
};
-/* reftable_new_writer creates a new writer */
-struct reftable_writer *
-reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
- int (*flush_func)(void *),
- void *writer_arg, const struct reftable_write_options *opts);
+struct reftable_writer;
+
+/* Create a new writer. */
+int reftable_writer_new(struct reftable_writer **out,
+ ssize_t (*writer_func)(void *, const void *, size_t),
+ int (*flush_func)(void *),
+ void *writer_arg, const struct reftable_write_options *opts);
/* Set the range of update indices for the records we will add. When writing a
table into a stack, the min should be at least
diff --git a/reftable/stack.c b/reftable/stack.c
index 84cf37a2ad..7e617c2591 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -56,10 +56,16 @@ static int reftable_fd_flush(void *arg)
int reftable_new_stack(struct reftable_stack **dest, const char *dir,
const struct reftable_write_options *_opts)
{
- struct reftable_stack *p = reftable_calloc(1, sizeof(*p));
struct strbuf list_file_name = STRBUF_INIT;
- struct reftable_write_options opts = {0};
- int err = 0;
+ struct reftable_write_options opts = { 0 };
+ struct reftable_stack *p;
+ int err;
+
+ p = reftable_calloc(1, sizeof(*p));
+ if (!p) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
if (_opts)
opts = *_opts;
@@ -74,15 +80,23 @@ int reftable_new_stack(struct reftable_stack **dest, const char *dir,
p->list_file = strbuf_detach(&list_file_name, NULL);
p->list_fd = -1;
- p->reftable_dir = xstrdup(dir);
p->opts = opts;
+ p->reftable_dir = reftable_strdup(dir);
+ if (!p->reftable_dir) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
err = reftable_stack_reload_maybe_reuse(p, 1);
- if (err < 0) {
+ if (err < 0)
+ goto out;
+
+ *dest = p;
+ err = 0;
+
+out:
+ if (err < 0)
reftable_stack_destroy(p);
- } else {
- *dest = p;
- }
return err;
}
@@ -102,13 +116,22 @@ static int fd_read_lines(int fd, char ***namesp)
}
REFTABLE_ALLOC_ARRAY(buf, size + 1);
+ if (!buf) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
if (read_in_full(fd, buf, size) != size) {
err = REFTABLE_IO_ERROR;
goto done;
}
buf[size] = 0;
- parse_names(buf, size, namesp);
+ *namesp = parse_names(buf, size);
+ if (!*namesp) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
done:
reftable_free(buf);
@@ -122,6 +145,8 @@ int read_lines(const char *filename, char ***namesp)
if (fd < 0) {
if (errno == ENOENT) {
REFTABLE_CALLOC_ARRAY(*namesp, 1);
+ if (!*namesp)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
return 0;
}
@@ -132,18 +157,18 @@ int read_lines(const char *filename, char ***namesp)
return err;
}
-void reftable_stack_init_ref_iterator(struct reftable_stack *st,
+int reftable_stack_init_ref_iterator(struct reftable_stack *st,
struct reftable_iterator *it)
{
- merged_table_init_iter(reftable_stack_merged_table(st),
- it, BLOCK_TYPE_REF);
+ return merged_table_init_iter(reftable_stack_merged_table(st),
+ it, BLOCK_TYPE_REF);
}
-void reftable_stack_init_log_iterator(struct reftable_stack *st,
- struct reftable_iterator *it)
+int reftable_stack_init_log_iterator(struct reftable_stack *st,
+ struct reftable_iterator *it)
{
- merged_table_init_iter(reftable_stack_merged_table(st),
- it, BLOCK_TYPE_LOG);
+ return merged_table_init_iter(reftable_stack_merged_table(st),
+ it, BLOCK_TYPE_LOG);
}
struct reftable_merged_table *
@@ -167,6 +192,10 @@ void reftable_stack_destroy(struct reftable_stack *st)
{
char **names = NULL;
int err = 0;
+
+ if (!st)
+ return;
+
if (st->merged) {
reftable_merged_table_free(st->merged);
st->merged = NULL;
@@ -174,7 +203,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
err = read_lines(st->list_file, &names);
if (err < 0) {
- FREE_AND_NULL(names);
+ REFTABLE_FREE_AND_NULL(names);
}
if (st->readers) {
@@ -195,7 +224,7 @@ void reftable_stack_destroy(struct reftable_stack *st)
}
strbuf_release(&filename);
st->readers_len = 0;
- FREE_AND_NULL(st->readers);
+ REFTABLE_FREE_AND_NULL(st->readers);
}
if (st->list_fd >= 0) {
@@ -203,20 +232,20 @@ void reftable_stack_destroy(struct reftable_stack *st)
st->list_fd = -1;
}
- FREE_AND_NULL(st->list_file);
- FREE_AND_NULL(st->reftable_dir);
+ REFTABLE_FREE_AND_NULL(st->list_file);
+ REFTABLE_FREE_AND_NULL(st->reftable_dir);
reftable_free(st);
free_names(names);
}
static struct reftable_reader **stack_copy_readers(struct reftable_stack *st,
- int cur_len)
+ size_t cur_len)
{
struct reftable_reader **cur = reftable_calloc(cur_len, sizeof(*cur));
- int i = 0;
- for (i = 0; i < cur_len; i++) {
+ if (!cur)
+ return NULL;
+ for (size_t i = 0; i < cur_len; i++)
cur[i] = st->readers[i];
- }
return cur;
}
@@ -225,18 +254,30 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
int reuse_open)
{
size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
- struct reftable_reader **cur = stack_copy_readers(st, cur_len);
+ struct reftable_reader **cur;
struct reftable_reader **reused = NULL;
- size_t reused_len = 0, reused_alloc = 0;
- size_t names_len = names_length(names);
- struct reftable_reader **new_readers =
- reftable_calloc(names_len, sizeof(*new_readers));
+ struct reftable_reader **new_readers;
+ size_t reused_len = 0, reused_alloc = 0, names_len;
size_t new_readers_len = 0;
struct reftable_merged_table *new_merged = NULL;
struct strbuf table_path = STRBUF_INIT;
int err = 0;
size_t i;
+ cur = stack_copy_readers(st, cur_len);
+ if (!cur) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ names_len = names_length(names);
+
+ new_readers = reftable_calloc(names_len, sizeof(*new_readers));
+ if (!new_readers) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
while (*names) {
struct reftable_reader *rd = NULL;
const char *name = *names++;
@@ -257,6 +298,10 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
* do by bumping their refcount.
*/
REFTABLE_ALLOC_GROW(reused, reused_len + 1, reused_alloc);
+ if (!reused) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
reused[reused_len++] = rd;
reftable_reader_incref(rd);
break;
@@ -382,6 +427,10 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
}
REFTABLE_CALLOC_ARRAY(names, 1);
+ if (!names) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto out;
+ }
} else {
err = fd_read_lines(fd, &names);
if (err < 0)
@@ -749,7 +798,11 @@ int reftable_stack_new_addition(struct reftable_addition **dest,
{
int err = 0;
struct reftable_addition empty = REFTABLE_ADDITION_INIT;
+
REFTABLE_CALLOC_ARRAY(*dest, 1);
+ if (!*dest)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
**dest = empty;
err = reftable_stack_init_addition(*dest, st, flags);
if (err) {
@@ -812,8 +865,11 @@ int reftable_addition_add(struct reftable_addition *add,
}
tab_fd = get_tempfile_fd(tab_file);
- wr = reftable_new_writer(reftable_fd_write, reftable_fd_flush, &tab_fd,
- &add->stack->opts);
+ err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
+ &tab_fd, &add->stack->opts);
+ if (err < 0)
+ goto done;
+
err = write_table(wr, arg);
if (err < 0)
goto done;
@@ -853,7 +909,12 @@ int reftable_addition_add(struct reftable_addition *add,
REFTABLE_ALLOC_GROW(add->new_tables, add->new_tables_len + 1,
add->new_tables_cap);
+ if (!add->new_tables) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
add->new_tables[add->new_tables_len++] = strbuf_detach(&next_name, NULL);
+
done:
delete_tempfile(&tab_file);
strbuf_release(&temp_tab_file_name);
@@ -902,8 +963,11 @@ static int stack_compact_locked(struct reftable_stack *st,
goto done;
}
- wr = reftable_new_writer(reftable_fd_write, reftable_fd_flush,
- &tab_fd, &st->opts);
+ err = reftable_writer_new(&wr, reftable_fd_write, reftable_fd_flush,
+ &tab_fd, &st->opts);
+ if (err < 0)
+ goto done;
+
err = stack_write_compact(st, wr, first, last, config);
if (err < 0)
goto done;
@@ -950,7 +1014,10 @@ static int stack_write_compact(struct reftable_stack *st,
if (err < 0)
goto done;
- merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
+ if (err < 0)
+ goto done;
+
err = reftable_iterator_seek_ref(&it, "");
if (err < 0)
goto done;
@@ -975,7 +1042,10 @@ static int stack_write_compact(struct reftable_stack *st,
}
reftable_iterator_destroy(&it);
- merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+ err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG);
+ if (err < 0)
+ goto done;
+
err = reftable_iterator_seek_log(&it, "");
if (err < 0)
goto done;
@@ -1091,6 +1161,11 @@ static int stack_compact_range(struct reftable_stack *st,
* from the point of view of the newer process.
*/
REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
+ if (!table_locks) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
for (i = last + 1; i > first; i--) {
stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
@@ -1274,8 +1349,18 @@ static int stack_compact_range(struct reftable_stack *st,
* thus have to allocate `readers_len + 1` many entries.
*/
REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
- for (size_t i = 0; i < st->merged->readers_len; i++)
- names[i] = xstrdup(st->readers[i]->name);
+ if (!names) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+
+ for (size_t i = 0; i < st->merged->readers_len; i++) {
+ names[i] = reftable_strdup(st->readers[i]->name);
+ if (!names[i]) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
+ }
first_to_replace = first;
last_to_replace = last;
}
@@ -1348,7 +1433,7 @@ static int stack_compact_range(struct reftable_stack *st,
struct lock_file *table_lock = &table_locks[i];
char *table_path = get_locked_file_path(table_lock);
unlink(table_path);
- free(table_path);
+ reftable_free(table_path);
}
done:
@@ -1465,6 +1550,8 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
uint64_t *sizes;
REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
+ if (!sizes)
+ return NULL;
for (size_t i = 0; i < st->merged->readers_len; i++)
sizes[i] = st->readers[i]->size - overhead;
@@ -1474,11 +1561,17 @@ static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
int reftable_stack_auto_compact(struct reftable_stack *st)
{
- uint64_t *sizes = stack_table_sizes_for_compaction(st);
- struct segment seg =
- suggest_compaction_segment(sizes, st->merged->readers_len,
- st->opts.auto_compaction_factor);
+ struct segment seg;
+ uint64_t *sizes;
+
+ sizes = stack_table_sizes_for_compaction(st);
+ if (!sizes)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
+ seg = suggest_compaction_segment(sizes, st->merged->readers_len,
+ st->opts.auto_compaction_factor);
reftable_free(sizes);
+
if (segment_size(&seg) > 0)
return stack_compact_range(st, seg.start, seg.end - 1,
NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
@@ -1498,7 +1591,10 @@ int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
struct reftable_iterator it = { 0 };
int ret;
- reftable_merged_table_init_ref_iterator(st->merged, &it);
+ ret = reftable_merged_table_init_ref_iterator(st->merged, &it);
+ if (ret)
+ goto out;
+
ret = reftable_iterator_seek_ref(&it, refname);
if (ret)
goto out;
@@ -1525,7 +1621,10 @@ int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
struct reftable_iterator it = {0};
int err;
- reftable_stack_init_log_iterator(st, &it);
+ err = reftable_stack_init_log_iterator(st, &it);
+ if (err)
+ goto done;
+
err = reftable_iterator_seek_log(&it, refname);
if (err)
goto done;
diff --git a/reftable/tree.c b/reftable/tree.c
index 5ffb2e0d69..f4dbe72090 100644
--- a/reftable/tree.c
+++ b/reftable/tree.c
@@ -11,28 +11,44 @@ https://developers.google.com/open-source/licenses/bsd
#include "basics.h"
-struct tree_node *tree_search(void *key, struct tree_node **rootp,
- int (*compare)(const void *, const void *),
- int insert)
+struct tree_node *tree_search(struct tree_node *tree,
+ void *key,
+ int (*compare)(const void *, const void *))
{
int res;
+ if (!tree)
+ return NULL;
+ res = compare(key, tree->key);
+ if (res < 0)
+ return tree_search(tree->left, key, compare);
+ else if (res > 0)
+ return tree_search(tree->right, key, compare);
+ return tree;
+}
+
+struct tree_node *tree_insert(struct tree_node **rootp,
+ void *key,
+ int (*compare)(const void *, const void *))
+{
+ int res;
+
if (!*rootp) {
- if (!insert) {
+ struct tree_node *n;
+
+ REFTABLE_CALLOC_ARRAY(n, 1);
+ if (!n)
return NULL;
- } else {
- struct tree_node *n;
- REFTABLE_CALLOC_ARRAY(n, 1);
- n->key = key;
- *rootp = n;
- return *rootp;
- }
+
+ n->key = key;
+ *rootp = n;
+ return *rootp;
}
res = compare(key, (*rootp)->key);
if (res < 0)
- return tree_search(key, &(*rootp)->left, compare, insert);
+ return tree_insert(&(*rootp)->left, key, compare);
else if (res > 0)
- return tree_search(key, &(*rootp)->right, compare, insert);
+ return tree_insert(&(*rootp)->right, key, compare);
return *rootp;
}
diff --git a/reftable/tree.h b/reftable/tree.h
index fbdd002e23..9604453b6d 100644
--- a/reftable/tree.h
+++ b/reftable/tree.h
@@ -15,12 +15,23 @@ struct tree_node {
struct tree_node *left, *right;
};
-/* looks for `key` in `rootp` using `compare` as comparison function. If insert
- * is set, insert the key if it's not found. Else, return NULL.
+/*
+ * Search the tree for the node matching the given key using `compare` as
+ * comparison function. Returns the node whose key matches or `NULL` in case
+ * the key does not exist in the tree.
+ */
+struct tree_node *tree_search(struct tree_node *tree,
+ void *key,
+ int (*compare)(const void *, const void *));
+
+/*
+ * Insert a node into the tree. Returns the newly inserted node if the key does
+ * not yet exist. Otherwise it returns the preexisting node. Returns `NULL`
+ * when allocating the new node fails.
*/
-struct tree_node *tree_search(void *key, struct tree_node **rootp,
- int (*compare)(const void *, const void *),
- int insert);
+struct tree_node *tree_insert(struct tree_node **rootp,
+ void *key,
+ int (*compare)(const void *, const void *));
/* performs an infix walk of the tree. */
void infix_walk(struct tree_node *t, void (*action)(void *arg, void *key),
diff --git a/reftable/writer.c b/reftable/writer.c
index 9d5e6072bc..b032a47dec 100644
--- a/reftable/writer.c
+++ b/reftable/writer.c
@@ -49,8 +49,14 @@ static int padded_write(struct reftable_writer *w, uint8_t *data, size_t len,
{
int n = 0;
if (w->pending_padding > 0) {
- uint8_t *zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
- int n = w->write(w->write_arg, zeroed, w->pending_padding);
+ uint8_t *zeroed;
+ int n;
+
+ zeroed = reftable_calloc(w->pending_padding, sizeof(*zeroed));
+ if (!zeroed)
+ return -1;
+
+ n = w->write(w->write_arg, zeroed, w->pending_padding);
if (n < 0)
return n;
@@ -102,28 +108,37 @@ static int writer_write_header(struct reftable_writer *w, uint8_t *dest)
return header_size(writer_version(w));
}
-static void writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
+static int writer_reinit_block_writer(struct reftable_writer *w, uint8_t typ)
{
- int block_start = 0;
- if (w->next == 0) {
+ int block_start = 0, ret;
+
+ if (w->next == 0)
block_start = header_size(writer_version(w));
- }
strbuf_reset(&w->last_key);
- block_writer_init(&w->block_writer_data, typ, w->block,
- w->opts.block_size, block_start,
- hash_size(w->opts.hash_id));
+ ret = block_writer_init(&w->block_writer_data, typ, w->block,
+ w->opts.block_size, block_start,
+ hash_size(w->opts.hash_id));
+ if (ret < 0)
+ return ret;
+
w->block_writer = &w->block_writer_data;
w->block_writer->restart_interval = w->opts.restart_interval;
+
+ return 0;
}
-struct reftable_writer *
-reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
- int (*flush_func)(void *),
- void *writer_arg, const struct reftable_write_options *_opts)
+int reftable_writer_new(struct reftable_writer **out,
+ ssize_t (*writer_func)(void *, const void *, size_t),
+ int (*flush_func)(void *),
+ void *writer_arg, const struct reftable_write_options *_opts)
{
- struct reftable_writer *wp = reftable_calloc(1, sizeof(*wp));
struct reftable_write_options opts = {0};
+ struct reftable_writer *wp;
+
+ wp = reftable_calloc(1, sizeof(*wp));
+ if (!wp)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
if (_opts)
opts = *_opts;
@@ -134,13 +149,19 @@ reftable_new_writer(ssize_t (*writer_func)(void *, const void *, size_t),
strbuf_init(&wp->block_writer_data.last_key, 0);
strbuf_init(&wp->last_key, 0);
REFTABLE_CALLOC_ARRAY(wp->block, opts.block_size);
+ if (!wp->block) {
+ reftable_free(wp);
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+ }
wp->write = writer_func;
wp->write_arg = writer_arg;
wp->opts = opts;
wp->flush = flush_func;
writer_reinit_block_writer(wp, BLOCK_TYPE_REF);
- return wp;
+ *out = wp;
+
+ return 0;
}
void reftable_writer_set_limits(struct reftable_writer *w, uint64_t min,
@@ -186,34 +207,40 @@ static int obj_index_tree_node_compare(const void *a, const void *b)
&((const struct obj_index_tree_node *)b)->hash);
}
-static void writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
+static int writer_index_hash(struct reftable_writer *w, struct strbuf *hash)
{
uint64_t off = w->next;
-
struct obj_index_tree_node want = { .hash = *hash };
+ struct obj_index_tree_node *key;
+ struct tree_node *node;
- struct tree_node *node = tree_search(&want, &w->obj_index_tree,
- &obj_index_tree_node_compare, 0);
- struct obj_index_tree_node *key = NULL;
+ node = tree_search(w->obj_index_tree, &want, &obj_index_tree_node_compare);
if (!node) {
struct obj_index_tree_node empty = OBJ_INDEX_TREE_NODE_INIT;
- key = reftable_malloc(sizeof(struct obj_index_tree_node));
+
+ key = reftable_malloc(sizeof(*key));
+ if (!key)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
*key = empty;
strbuf_reset(&key->hash);
strbuf_addbuf(&key->hash, hash);
- tree_search((void *)key, &w->obj_index_tree,
- &obj_index_tree_node_compare, 1);
+ tree_insert(&w->obj_index_tree, key,
+ &obj_index_tree_node_compare);
} else {
key = node->key;
}
- if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off) {
- return;
- }
+ if (key->offset_len > 0 && key->offsets[key->offset_len - 1] == off)
+ return 0;
REFTABLE_ALLOC_GROW(key->offsets, key->offset_len + 1, key->offset_cap);
+ if (!key->offsets)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
key->offsets[key->offset_len++] = off;
+
+ return 0;
}
static int writer_add_record(struct reftable_writer *w,
@@ -230,8 +257,11 @@ static int writer_add_record(struct reftable_writer *w,
strbuf_reset(&w->last_key);
strbuf_addbuf(&w->last_key, &key);
- if (!w->block_writer)
- writer_reinit_block_writer(w, reftable_record_type(rec));
+ if (!w->block_writer) {
+ err = writer_reinit_block_writer(w, reftable_record_type(rec));
+ if (err < 0)
+ goto done;
+ }
if (block_writer_type(w->block_writer) != reftable_record_type(rec))
BUG("record of type %d added to writer of type %d",
@@ -254,7 +284,9 @@ static int writer_add_record(struct reftable_writer *w,
err = writer_flush_block(w);
if (err < 0)
goto done;
- writer_reinit_block_writer(w, reftable_record_type(rec));
+ err = writer_reinit_block_writer(w, reftable_record_type(rec));
+ if (err < 0)
+ goto done;
/*
* Try to add the record to the writer again. If this still fails then
@@ -284,11 +316,11 @@ int reftable_writer_add_ref(struct reftable_writer *w,
.ref = *ref
},
};
- int err = 0;
+ struct strbuf buf = STRBUF_INIT;
+ int err;
- if (!ref->refname)
- return REFTABLE_API_ERROR;
- if (ref->update_index < w->min_update_index ||
+ if (!ref->refname ||
+ ref->update_index < w->min_update_index ||
ref->update_index > w->max_update_index)
return REFTABLE_API_ERROR;
@@ -296,24 +328,32 @@ int reftable_writer_add_ref(struct reftable_writer *w,
err = writer_add_record(w, &rec);
if (err < 0)
- return err;
+ goto out;
if (!w->opts.skip_index_objects && reftable_ref_record_val1(ref)) {
- struct strbuf h = STRBUF_INIT;
- strbuf_add(&h, (char *)reftable_ref_record_val1(ref),
+ strbuf_add(&buf, (char *)reftable_ref_record_val1(ref),
hash_size(w->opts.hash_id));
- writer_index_hash(w, &h);
- strbuf_release(&h);
+
+ err = writer_index_hash(w, &buf);
+ if (err < 0)
+ goto out;
}
if (!w->opts.skip_index_objects && reftable_ref_record_val2(ref)) {
- struct strbuf h = STRBUF_INIT;
- strbuf_add(&h, reftable_ref_record_val2(ref),
+ strbuf_reset(&buf);
+ strbuf_add(&buf, reftable_ref_record_val2(ref),
hash_size(w->opts.hash_id));
- writer_index_hash(w, &h);
- strbuf_release(&h);
+
+ err = writer_index_hash(w, &buf);
+ if (err < 0)
+ goto out;
}
- return 0;
+
+ err = 0;
+
+out:
+ strbuf_release(&buf);
+ return err;
}
int reftable_writer_add_refs(struct reftable_writer *w,
@@ -436,7 +476,9 @@ static int writer_finish_section(struct reftable_writer *w)
max_level++;
index_start = w->next;
- writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
+ err = writer_reinit_block_writer(w, BLOCK_TYPE_INDEX);
+ if (err < 0)
+ return err;
idx = w->index;
idx_len = w->index_len;
@@ -530,7 +572,10 @@ static void write_object_record(void *void_arg, void *key)
if (arg->err < 0)
goto done;
- writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
+ arg->err = writer_reinit_block_writer(arg->w, BLOCK_TYPE_OBJ);
+ if (arg->err < 0)
+ goto done;
+
arg->err = block_writer_add(arg->w->block_writer, &rec);
if (arg->err == 0)
goto done;
@@ -548,7 +593,7 @@ static void object_record_free(void *void_arg UNUSED, void *key)
{
struct obj_index_tree_node *entry = key;
- FREE_AND_NULL(entry->offsets);
+ REFTABLE_FREE_AND_NULL(entry->offsets);
strbuf_release(&entry->hash);
reftable_free(entry);
}
@@ -559,16 +604,18 @@ static int writer_dump_object_index(struct reftable_writer *w)
struct common_prefix_arg common = {
.max = 1, /* obj_id_len should be >= 2. */
};
- if (w->obj_index_tree) {
+ int err;
+
+ if (w->obj_index_tree)
infix_walk(w->obj_index_tree, &update_common, &common);
- }
w->stats.object_id_len = common.max + 1;
- writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
+ err = writer_reinit_block_writer(w, BLOCK_TYPE_OBJ);
+ if (err < 0)
+ return err;
- if (w->obj_index_tree) {
+ if (w->obj_index_tree)
infix_walk(w->obj_index_tree, &write_object_record, &closure);
- }
if (closure.err < 0)
return closure.err;
@@ -662,7 +709,7 @@ static void writer_clear_index(struct reftable_writer *w)
{
for (size_t i = 0; w->index && i < w->index_len; i++)
strbuf_release(&w->index[i].last_key);
- FREE_AND_NULL(w->index);
+ REFTABLE_FREE_AND_NULL(w->index);
w->index_len = 0;
w->index_cap = 0;
}
@@ -726,6 +773,9 @@ static int writer_flush_nonempty_block(struct reftable_writer *w)
* case we will end up with a multi-level index.
*/
REFTABLE_ALLOC_GROW(w->index, w->index_len + 1, w->index_cap);
+ if (!w->index)
+ return REFTABLE_OUT_OF_MEMORY_ERROR;
+
index_record.offset = w->next;
strbuf_reset(&index_record.last_key);
strbuf_addbuf(&index_record.last_key, &w->block_writer->last_key);