fsck: check rev-index position values

When checking a rev-index file, it may be helpful to identify exactly which positions are incorrect. Compare the rev-index to a freshly-computed in-memory rev-index and report the comparison failures. This additional check (on top of the checksum validation) can help find files that were corrupt by a single bit flip on-disk or perhaps were written incorrectly due to a bug in Git. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Apr 17, 2023 at 16:21 UTC 5f658d1b577722111564f51962d6af33d1fe96c6
2 files changed +26 -4
pack-revindex.c
+21 -4
@@ -310,16 +310,33 @@ int load_pack_revindex(struct repository *r, struct packed_git *p)
310 */
311 int verify_pack_revindex(struct packed_git *p)
312 {
313 + int res = 0;
314 +
315 /* Do not bother checking if not initialized. */
314 - if (!p->revindex_map)
315 - return 0;
316 + if (!p->revindex_map || !p->revindex_data)
317 + return res;
318
319 if (!hashfile_checksum_valid((const unsigned char *)p->revindex_map, p->revindex_size)) {
320 error(_("invalid checksum"));
319 - return -1;
321 + res = -1;
322 }
323
322 - return 0;
324 + /* This may fail due to a broken .idx. */
325 + if (create_pack_revindex_in_memory(p))
326 + return res;
327 +
328 + for (size_t i = 0; i < p->num_objects; i++) {
329 + uint32_t nr = p->revindex[i].nr;
330 + uint32_t rev_val = get_be32(p->revindex_data + i);
331 +
332 + if (nr != rev_val) {
333 + error(_("invalid rev-index position at %"PRIu64": %"PRIu32" != %"PRIu32""),
334 + (uint64_t)i, nr, rev_val);
335 + res = -1;
336 + }
337 + }
338 +
339 + return res;
340 }
341
342 int load_midx_revindex(struct multi_pack_index *m)
t/t5325-reverse-index.sh
+5
@@ -185,4 +185,9 @@ test_expect_success 'fsck catches invalid checksum' '
185 "invalid checksum"
186 '
187
188 +test_expect_success 'fsck catches invalid row position' '
189 + corrupt_rev_and_verify 14 "\07" \
190 + "invalid rev-index position"
191 +'
192 +
193 test_done