[PATCH v3 4/8] reftable: ensure tables in a stack use sequential update indices
- From
Karthik Nayak <karthik.188@gmail.com>
- Date
- Sep 18, 2025, 08:11 UTC
- Message-ID
- <20250918-228-reftable-introduce-consistency-checks-v3-4-271af03eb34d@gmail.com>
- In-Reply-To
- <20250918-228-reftable-introduce-consistency-checks-v3-0-271af03eb34d@gmail.com>
When tables are loaded into a stack, we expect that the tables are sequentially ordered by their update indices. But there is no validation done for this. Add validation to ensure that tables loaded are sequential.
Raise a 'REFTABLE_FORMAT_ERROR' when this validation fails.
Signed-off-by: Karthik Nayak <karthik.188@gmail.com> --- reftable/stack.c | 9 +++++++++ t/unit-tests/u-reftable-stack.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+)
diff --git a/reftable/stack.c b/reftable/stack.c index 955be1edb6..a458f5a4c5 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -238,6 +238,7 @@ static int reftable_stack_reload_once(struct reftable_stack *st, int reuse_open) { size_t cur_len = !st->merged ? 0 : st->merged->tables_len; + const struct reftable_table *prev_table = NULL; struct reftable_table **cur = NULL; struct reftable_table **reused = NULL; struct reftable_table **new_tables = NULL; @@ -317,6 +318,14 @@ static int reftable_stack_reload_once(struct reftable_stack *st, new_tables[new_tables_len] = table; new_tables_len++; + + /* table's update indices must be sequential */ + if (prev_table && (prev_table->max_update_index != table->min_update_index - 1)) { + err = REFTABLE_FORMAT_ERROR; + goto done; + } + + prev_table = table; } /* success! */ diff --git a/t/unit-tests/u-reftable-stack.c b/t/unit-tests/u-reftable-stack.c index a8b91812e8..465f4a2689 100644 --- a/t/unit-tests/u-reftable-stack.c +++ b/t/unit-tests/u-reftable-stack.c @@ -1330,3 +1330,31 @@ void test_reftable_stack__invalid_limit_updates(void) reftable_stack_destroy(st); clear_dir(dir); } + +void test_reftable_stack__non_seq_update_indices(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_stack *st1 = NULL; + char *dir = get_tmp_dir(__LINE__); + + struct reftable_ref_record ref1 = { + .refname = (char *)"HEAD", + .update_index = 1, + .value_type = REFTABLE_REF_SYMREF, + .value.symref = (char *)"master", + }; + struct reftable_ref_record ref2 = { + .refname = (char *)"branch2", + .update_index = 3, + .value_type = REFTABLE_REF_SYMREF, + .value.symref = (char *)"master", + }; + + cl_assert_equal_i(reftable_new_stack(&st1, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_add(st1, write_test_ref, &ref1, 0), 0); + cl_assert_equal_i(reftable_stack_add(st1, write_test_ref, &ref2, 0), + REFTABLE_FORMAT_ERROR); + + reftable_stack_destroy(st1); + clear_dir(dir); +}
-- 2.51.0