reftable: signal overflow

reflog entries have unbounded size. In theory, each log ('g') block in reftable
can have an arbitrary size, so the format allows for arbitrarily sized reflog
messages. However, in the implementation, we are not scaling the log blocks up
with the message, and writing a large message fails.

This triggers a failure for reftable in t7006-pager.sh.

Until this is fixed more structurally, report an error from within the reftable
library for easier debugging.

Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Han-Wen Nienhuys 2021-12-23 19:29:49 +00:00 committed by Junio C Hamano
parent 019bd34082
commit 0dd44584ab
4 changed files with 44 additions and 0 deletions

View File

@ -32,6 +32,8 @@ const char *reftable_error_str(int err)
return "wrote empty table";
case REFTABLE_REFNAME_ERROR:
return "invalid refname";
case REFTABLE_ENTRY_TOO_BIG_ERROR:
return "entry too large";
case -1:
return "general error";
default:

View File

@ -155,6 +155,40 @@ static void test_log_buffer_size(void)
strbuf_release(&buf);
}
static void test_log_overflow(void)
{
struct strbuf buf = STRBUF_INIT;
char msg[256] = { 0 };
struct reftable_write_options opts = {
.block_size = ARRAY_SIZE(msg),
};
int err;
struct reftable_log_record
log = { .refname = "refs/heads/master",
.update_index = 0xa,
.value_type = REFTABLE_LOG_UPDATE,
.value = { .update = {
.name = "Han-Wen Nienhuys",
.email = "hanwen@google.com",
.tz_offset = 100,
.time = 0x5e430672,
.message = msg,
} } };
struct reftable_writer *w =
reftable_new_writer(&strbuf_add_void, &buf, &opts);
uint8_t hash1[GIT_SHA1_RAWSZ] = {1}, hash2[GIT_SHA1_RAWSZ] = { 2 };
memset(msg, 'x', sizeof(msg) - 1);
log.value.update.old_hash = hash1;
log.value.update.new_hash = hash2;
reftable_writer_set_limits(w, update_index, update_index);
err = reftable_writer_add_log(w, &log);
EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
reftable_writer_free(w);
strbuf_release(&buf);
}
static void test_log_write_read(void)
{
int N = 2;
@ -648,5 +682,6 @@ int readwrite_test_main(int argc, const char *argv[])
RUN_TEST(test_table_refs_for_no_index);
RUN_TEST(test_table_refs_for_obj_index);
RUN_TEST(test_write_empty_table);
RUN_TEST(test_log_overflow);
return 0;
}

View File

@ -53,6 +53,10 @@ enum reftable_error {
/* Invalid ref name. */
REFTABLE_REFNAME_ERROR = -10,
/* Entry does not fit. This can happen when writing outsize reflog
messages. */
REFTABLE_ENTRY_TOO_BIG_ERROR = -11,
};
/* convert the numeric error code to a string. The string should not be

View File

@ -239,6 +239,9 @@ static int writer_add_record(struct reftable_writer *w,
writer_reinit_block_writer(w, reftable_record_type(rec));
err = block_writer_add(w->block_writer, rec);
if (err < 0) {
/* we are writing into memory, so an error can only mean it
* doesn't fit. */
err = REFTABLE_ENTRY_TOO_BIG_ERROR;
goto done;
}