Skip to content

Commit 49c6b91

Browse files
KarthikNayakgitster
authored andcommitted
reftable/writer: ensure valid range for log's update_index
Each reftable addition has an associated update_index. While writing refs, the update_index is verified to be within the range of the reftable writer, i.e. `writer.min_update_index <= ref.update_index` and `writer.max_update_index => ref.update_index`. The corresponding check for reflogs in `reftable_writer_add_log` is however missing. Add a similar check, but only check for the upper limit. This is because reflogs are treated a bit differently than refs. Each reflog entry in reftable has an associated update_index and we also allow expiring entries in the middle, which is done by simply writing a new reflog entry with the same update_index. This means, writing reflog entries with update_index lesser than the writer's update_index is an expected scenario. Add a new unit test to check for the limits and fix some of the existing tests, which were setting arbitrary values for the update_index by ensuring they stay within the now checked limits. Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent cc01bad commit 49c6b91

File tree

3 files changed

+63
-4
lines changed

3 files changed

+63
-4
lines changed

Diff for: reftable/writer.c

+12
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,18 @@ int reftable_writer_add_log(struct reftable_writer *w,
412412
if (log->value_type == REFTABLE_LOG_DELETION)
413413
return reftable_writer_add_log_verbatim(w, log);
414414

415+
/*
416+
* Verify only the upper limit of the update_index. Each reflog entry
417+
* is tied to a specific update_index. Entries in the reflog can be
418+
* replaced by adding a new entry with the same update_index,
419+
* effectively canceling the old one.
420+
*
421+
* Consequently, reflog updates may include update_index values lower
422+
* than the writer's min_update_index.
423+
*/
424+
if (log->update_index > w->max_update_index)
425+
return REFTABLE_API_ERROR;
426+
415427
if (!log->refname)
416428
return REFTABLE_API_ERROR;
417429

Diff for: t/unit-tests/t-reftable-readwrite.c

+45-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static void t_log_buffer_size(void)
9090
int i;
9191
struct reftable_log_record
9292
log = { .refname = (char *) "refs/heads/master",
93-
.update_index = 0xa,
93+
.update_index = update_index,
9494
.value_type = REFTABLE_LOG_UPDATE,
9595
.value = { .update = {
9696
.name = (char *) "Han-Wen Nienhuys",
@@ -127,7 +127,7 @@ static void t_log_overflow(void)
127127
int err;
128128
struct reftable_log_record log = {
129129
.refname = (char *) "refs/heads/master",
130-
.update_index = 0xa,
130+
.update_index = update_index,
131131
.value_type = REFTABLE_LOG_UPDATE,
132132
.value = {
133133
.update = {
@@ -151,6 +151,48 @@ static void t_log_overflow(void)
151151
reftable_buf_release(&buf);
152152
}
153153

154+
static void t_log_write_limits(void)
155+
{
156+
struct reftable_write_options opts = { 0 };
157+
struct reftable_buf buf = REFTABLE_BUF_INIT;
158+
struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts);
159+
struct reftable_log_record log = {
160+
.refname = (char *)"refs/head/master",
161+
.update_index = 0,
162+
.value_type = REFTABLE_LOG_UPDATE,
163+
.value = {
164+
.update = {
165+
.old_hash = { 1 },
166+
.new_hash = { 2 },
167+
.name = (char *)"Han-Wen Nienhuys",
168+
.email = (char *)"[email protected]",
169+
.tz_offset = 100,
170+
.time = 0x5e430672,
171+
},
172+
},
173+
};
174+
int err;
175+
176+
reftable_writer_set_limits(w, 1, 1);
177+
178+
/* write with update_index (0) below set limits (1, 1) */
179+
err = reftable_writer_add_log(w, &log);
180+
check_int(err, ==, 0);
181+
182+
/* write with update_index (1) in the set limits (1, 1) */
183+
log.update_index = 1;
184+
err = reftable_writer_add_log(w, &log);
185+
check_int(err, ==, 0);
186+
187+
/* write with update_index (3) above set limits (1, 1) */
188+
log.update_index = 3;
189+
err = reftable_writer_add_log(w, &log);
190+
check_int(err, ==, REFTABLE_API_ERROR);
191+
192+
reftable_writer_free(w);
193+
reftable_buf_release(&buf);
194+
}
195+
154196
static void t_log_write_read(void)
155197
{
156198
struct reftable_write_options opts = {
@@ -917,6 +959,7 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
917959
TEST(t_corrupt_table_empty(), "read-write on an empty table");
918960
TEST(t_log_buffer_size(), "buffer extension for log compression");
919961
TEST(t_log_overflow(), "log overflow returns expected error");
962+
TEST(t_log_write_limits(), "writer limits for writing log records");
920963
TEST(t_log_write_read(), "read-write on log records");
921964
TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error");
922965
TEST(t_table_read_api(), "read on a table");

Diff for: t/unit-tests/t-reftable-stack.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -770,8 +770,12 @@ static void t_reftable_stack_tombstone(void)
770770
}
771771

772772
logs[i].refname = xstrdup(buf);
773-
/* update_index is part of the key. */
774-
logs[i].update_index = 42;
773+
/*
774+
* update_index is part of the key so should be constant.
775+
* The value itself should be less than the writer's upper
776+
* limit.
777+
*/
778+
logs[i].update_index = 1;
775779
if (i % 2 == 0) {
776780
logs[i].value_type = REFTABLE_LOG_UPDATE;
777781
t_reftable_set_hash(logs[i].value.update.new_hash, i,

0 commit comments

Comments
 (0)