Skip to content

Commit 90cb1c4

Browse files
derrickstoleegitster
authored andcommitted
commit-graph: always parse before commit_graph_data_at()
There is a subtle failure happening when computing corrected commit dates with --split enabled. It requires a base layer needing the generation_data_overflow chunk. Then, the next layer on top erroneously thinks it needs an overflow chunk due to a bug leading to recalculating all reachable generation numbers. The output of the failure is BUG: commit-graph.c:1912: expected to write 8 bytes to chunk 47444f56, but wrote 0 instead These "expected" 8 bytes are due to re-computing the corrected commit date for the lower layer but the new layer does not need any overflow. Add a test to t5318-commit-graph.sh that demonstrates this bug. However, it does not trigger consistently with the existing code. The generation number data is stored in a slab and accessed by commit_graph_data_at(). This data is initialized when parsing a commit, but is otherwise used assuming it has been populated. The loop in compute_generation_numbers() did not enforce that all reachable commits were parsed and had correct values. This could lead to some problems when writing a commit-graph with corrected commit dates based on a commit-graph without them. It has been difficult to identify the issue here because it was so hard to reproduce. It relies on this uninitialized data having a non-zero value, but also on specifically in a way that overwrites the existing data. This patch adds the extra parse to ensure the data is filled before we compute the generation number of a commit. This triggers the new test to fail because the generation number overflow count does not match between this computation and the write for that chunk. The actual fix will follow as the next few changes. Signed-off-by: Derrick Stolee <[email protected]> Reviewed-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c4cc083 commit 90cb1c4

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

commit-graph.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,
11931193

11941194
for (i = 0; i < ctx->commits.nr; i++) {
11951195
struct commit *c = ctx->commits.list[i];
1196-
timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
1196+
timestamp_t offset;
1197+
repo_parse_commit(ctx->r, c);
1198+
offset = commit_graph_data_at(c)->generation - c->date;
11971199
display_progress(ctx->progress, ++ctx->progress_cnt);
11981200

11991201
if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
@@ -1444,15 +1446,20 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
14441446
_("Computing commit graph generation numbers"),
14451447
ctx->commits.nr);
14461448
for (i = 0; i < ctx->commits.nr; i++) {
1447-
uint32_t level = *topo_level_slab_at(ctx->topo_levels, ctx->commits.list[i]);
1448-
timestamp_t corrected_commit_date = commit_graph_data_at(ctx->commits.list[i])->generation;
1449+
struct commit *c = ctx->commits.list[i];
1450+
uint32_t level;
1451+
timestamp_t corrected_commit_date;
1452+
1453+
repo_parse_commit(ctx->r, c);
1454+
level = *topo_level_slab_at(ctx->topo_levels, c);
1455+
corrected_commit_date = commit_graph_data_at(c)->generation;
14491456

14501457
display_progress(ctx->progress, i + 1);
14511458
if (level != GENERATION_NUMBER_ZERO &&
14521459
corrected_commit_date != GENERATION_NUMBER_ZERO)
14531460
continue;
14541461

1455-
commit_list_insert(ctx->commits.list[i], &list);
1462+
commit_list_insert(c, &list);
14561463
while (list) {
14571464
struct commit *current = list->item;
14581465
struct commit_list *parent;
@@ -1461,6 +1468,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
14611468
timestamp_t max_corrected_commit_date = 0;
14621469

14631470
for (parent = current->parents; parent; parent = parent->next) {
1471+
repo_parse_commit(ctx->r, parent->item);
14641472
level = *topo_level_slab_at(ctx->topo_levels, parent->item);
14651473
corrected_commit_date = commit_graph_data_at(parent->item)->generation;
14661474

t/t5318-commit-graph.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,27 @@ test_expect_success 'warn on improper hash version' '
446446
)
447447
'
448448

449+
test_expect_failure 'lower layers have overflow chunk' '
450+
cd "$TRASH_DIRECTORY/full" &&
451+
UNIX_EPOCH_ZERO="@0 +0000" &&
452+
FUTURE_DATE="@2147483646 +0000" &&
453+
rm -f .git/objects/info/commit-graph &&
454+
test_commit --date "$FUTURE_DATE" future-1 &&
455+
test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
456+
git commit-graph write --reachable &&
457+
test_commit --date "$FUTURE_DATE" future-2 &&
458+
test_commit --date "$UNIX_EPOCH_ZERO" old-2 &&
459+
git commit-graph write --reachable --split=no-merge &&
460+
test_commit extra &&
461+
git commit-graph write --reachable --split=no-merge &&
462+
git commit-graph write --reachable &&
463+
graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
464+
mv .git/objects/info/commit-graph commit-graph-upgraded &&
465+
git commit-graph write --reachable &&
466+
graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
467+
test_cmp .git/objects/info/commit-graph commit-graph-upgraded
468+
'
469+
449470
# the verify tests below expect the commit-graph to contain
450471
# exactly the commits reachable from the commits/8 branch.
451472
# If the file changes the set of commits in the list, then the

0 commit comments

Comments
 (0)