While running 'git commit-graph verify', verify that the object IDs
are listed in lexicographic order and that the fanout table correctly
navigates into that list of object IDs.

Add tests that check these corruptions are caught by the verify
subcommand. Most of the tests check the full output matches the exact
error we inserted, but since our OID order test triggers incorrect
fanout values (with possibly different numbers of output lines) we
focus only that the correct error is written in that case.

Signed-off-by: Derrick Stolee <dsto...@microsoft.com>
---
 commit-graph.c          | 36 ++++++++++++++++++++++++++++++++++++
 t/t5318-commit-graph.sh | 31 +++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/commit-graph.c b/commit-graph.c
index 4dfff7e752..b0fd1d5320 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -848,6 +848,9 @@ static void graph_report(const char *fmt, ...)
 
 int verify_commit_graph(struct commit_graph *g)
 {
+       uint32_t i, cur_fanout_pos = 0;
+       struct object_id prev_oid, cur_oid;
+
        if (!g) {
                graph_report("no commit-graph file loaded");
                return 1;
@@ -862,5 +865,38 @@ int verify_commit_graph(struct commit_graph *g)
        if (!g->chunk_commit_data)
                graph_report("commit-graph is missing the Commit Data chunk");
 
+       if (verify_commit_graph_error)
+               return 1;
+
+       for (i = 0; i < g->num_commits; i++) {
+               hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
+
+               if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
+                       graph_report("commit-graph has incorrect oid order: %s 
then %s",
+                                    oid_to_hex(&prev_oid),
+                                    oid_to_hex(&cur_oid));
+
+               oidcpy(&prev_oid, &cur_oid);
+
+               while (cur_oid.hash[0] > cur_fanout_pos) {
+                       uint32_t fanout_value = get_be32(g->chunk_oid_fanout + 
cur_fanout_pos);
+                       if (i != fanout_value)
+                               graph_report("commit-graph has incorrect fanout 
value: fanout[%d] = %u != %u",
+                                            cur_fanout_pos, fanout_value, i);
+
+                       cur_fanout_pos++;
+               }
+       }
+
+       while (cur_fanout_pos < 256) {
+               uint32_t fanout_value = get_be32(g->chunk_oid_fanout + 
cur_fanout_pos);
+
+               if (g->num_commits != fanout_value)
+                       graph_report("commit-graph has incorrect fanout value: 
fanout[%d] = %u != %u",
+                                    cur_fanout_pos, fanout_value, i);
+
+               cur_fanout_pos++;
+       }
+
        return verify_commit_graph_error;
 }
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 0cb88232fa..6fb306b0da 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -293,4 +293,35 @@ test_expect_success 'detect too small chunk-count' '
        grep "missing the Commit Data chunk" verify-errors
 '
 
+test_expect_success 'detect incorrect chunk lookup value' '
+       cd "$TRASH_DIRECTORY/full" &&
+       cp $objdir/info/commit-graph commit-graph-backup &&
+       test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
+       corrupt_data $objdir/info/commit-graph 25 "\01" &&
+       test_must_fail git commit-graph verify 2>err &&
+       grep -v "^\+" err > verify-errors &&
+       test_line_count = 1 verify-errors &&
+       grep "improper chunk offset" verify-errors
+'
+
+test_expect_success 'detect incorrect fanout' '
+       cd "$TRASH_DIRECTORY/full" &&
+       cp $objdir/info/commit-graph commit-graph-backup &&
+       test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
+       corrupt_data $objdir/info/commit-graph 128 "\01" &&
+       test_must_fail git commit-graph verify 2>err &&
+       grep -v "^\+" err > verify-errors &&
+       test_line_count = 1 verify-errors &&
+       grep "fanout value" verify-errors
+'
+
+test_expect_success 'detect incorrect OID order' '
+       cd "$TRASH_DIRECTORY/full" &&
+       cp $objdir/info/commit-graph commit-graph-backup &&
+       test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
+       corrupt_data $objdir/info/commit-graph 1272 "\01" &&
+       test_must_fail git commit-graph verify 2>err &&
+       grep "incorrect oid order" err
+'
+
 test_done
-- 
2.16.2.329.gfb62395de6

Reply via email to