pack-bitmap.c: harden 'test_bitmap_walk()' to check type bitmaps

The special `--test-bitmap` mode of `git rev-list` is used to compare the result of an object traversal with a bitmap to check its integrity. This mode does not, however, assert that the types of reachable objects are stored correctly. Harden this mode by teaching it to also check that each time an object's bit is marked, the corresponding bit should be set in exactly one of the type bitmaps (whose type matches the object's true type). Co-authored-by: Jeff King <peff@peff.net> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Aug 24, 2021 at 12:15 UTC fa95666a403e5dda4c2c14ac168b5c3389126e6c
1 file changed +48
pack-bitmap.c
+48
@@ -1325,10 +1325,52 @@ void count_bitmap_commit_list(struct bitmap_index *bitmap_git,
1325 struct bitmap_test_data {
1326 struct bitmap_index *bitmap_git;
1327 struct bitmap *base;
1328 + struct bitmap *commits;
1329 + struct bitmap *trees;
1330 + struct bitmap *blobs;
1331 + struct bitmap *tags;
1332 struct progress *prg;
1333 size_t seen;
1334 };
1335
1336 +static void test_bitmap_type(struct bitmap_test_data *tdata,
1337 + struct object *obj, int pos)
1338 +{
1339 + enum object_type bitmap_type = OBJ_NONE;
1340 + int bitmaps_nr = 0;
1341 +
1342 + if (bitmap_get(tdata->commits, pos)) {
1343 + bitmap_type = OBJ_COMMIT;
1344 + bitmaps_nr++;
1345 + }
1346 + if (bitmap_get(tdata->trees, pos)) {
1347 + bitmap_type = OBJ_TREE;
1348 + bitmaps_nr++;
1349 + }
1350 + if (bitmap_get(tdata->blobs, pos)) {
1351 + bitmap_type = OBJ_BLOB;
1352 + bitmaps_nr++;
1353 + }
1354 + if (bitmap_get(tdata->tags, pos)) {
1355 + bitmap_type = OBJ_TAG;
1356 + bitmaps_nr++;
1357 + }
1358 +
1359 + if (bitmap_type == OBJ_NONE)
1360 + die("object %s not found in type bitmaps",
1361 + oid_to_hex(&obj->oid));
1362 +
1363 + if (bitmaps_nr > 1)
1364 + die("object %s does not have a unique type",
1365 + oid_to_hex(&obj->oid));
1366 +
1367 + if (bitmap_type != obj->type)
1368 + die("object %s: real type %s, expected: %s",
1369 + oid_to_hex(&obj->oid),
1370 + type_name(obj->type),
1371 + type_name(bitmap_type));
1372 +}
1373 +
1374 static void test_show_object(struct object *object, const char *name,
1375 void *data)
1376 {
@@ -1338,6 +1380,7 @@ static void test_show_object(struct object *object, const char *name,
1380 bitmap_pos = bitmap_position(tdata->bitmap_git, &object->oid);
1381 if (bitmap_pos < 0)
1382 die("Object not in bitmap: %s\n", oid_to_hex(&object->oid));
1383 + test_bitmap_type(tdata, object, bitmap_pos);
1384
1385 bitmap_set(tdata->base, bitmap_pos);
1386 display_progress(tdata->prg, ++tdata->seen);
@@ -1352,6 +1395,7 @@ static void test_show_commit(struct commit *commit, void *data)
1395 &commit->object.oid);
1396 if (bitmap_pos < 0)
1397 die("Object not in bitmap: %s\n", oid_to_hex(&commit->object.oid));
1398 + test_bitmap_type(tdata, &commit->object, bitmap_pos);
1399
1400 bitmap_set(tdata->base, bitmap_pos);
1401 display_progress(tdata->prg, ++tdata->seen);
@@ -1399,6 +1443,10 @@ void test_bitmap_walk(struct rev_info *revs)
1443
1444 tdata.bitmap_git = bitmap_git;
1445 tdata.base = bitmap_new();
1446 + tdata.commits = ewah_to_bitmap(bitmap_git->commits);
1447 + tdata.trees = ewah_to_bitmap(bitmap_git->trees);
1448 + tdata.blobs = ewah_to_bitmap(bitmap_git->blobs);
1449 + tdata.tags = ewah_to_bitmap(bitmap_git->tags);
1450 tdata.prg = start_progress("Verifying bitmap entries", result_popcnt);
1451 tdata.seen = 0;
1452