Handle allocation failures when decoding records. While at it, fix some error codes to be `REFTABLE_FORMAT_ERROR`. Signed-off-by: Patrick Steinhardt <ps@xxxxxx> --- reftable/record.c | 80 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/reftable/record.c b/reftable/record.c index 60fd33c9c9..787e134c9a 100644 --- a/reftable/record.c +++ b/reftable/record.c @@ -359,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); @@ -375,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; @@ -383,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); @@ -392,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); @@ -405,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); @@ -419,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) @@ -552,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; @@ -570,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); @@ -801,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); @@ -829,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); @@ -838,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); /* @@ -850,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) -- 2.47.0.rc0.dirty