Skip to content

Commit c0d7923

Browse files
[2.50.1] midx-write: fix segfault and other cleanups (#790)
This is a copy of #787 but for the 2.50.1 branch.
2 parents 336bf91 + 1b1942d commit c0d7923

File tree

2 files changed

+75
-60
lines changed

2 files changed

+75
-60
lines changed

midx-write.c

Lines changed: 58 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#define DISABLE_SIGN_COMPARE_WARNINGS
2-
31
#include "git-compat-util.h"
42
#include "abspath.h"
53
#include "config.h"
@@ -24,6 +22,7 @@
2422
#define BITMAP_POS_UNKNOWN (~((uint32_t)0))
2523
#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
2624
#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
25+
#define NO_PREFERRED_PACK (~((uint32_t)0))
2726

2827
extern int midx_checksum_valid(struct multi_pack_index *m);
2928
extern void clear_midx_files_ext(const char *object_dir, const char *ext,
@@ -104,7 +103,7 @@ struct write_midx_context {
104103
unsigned large_offsets_needed:1;
105104
uint32_t num_large_offsets;
106105

107-
int preferred_pack_idx;
106+
uint32_t preferred_pack_idx;
108107

109108
int incremental;
110109
uint32_t num_multi_pack_indexes_before;
@@ -260,7 +259,7 @@ static void midx_fanout_sort(struct midx_fanout *fanout)
260259
static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
261260
struct multi_pack_index *m,
262261
uint32_t cur_fanout,
263-
int preferred_pack)
262+
uint32_t preferred_pack)
264263
{
265264
uint32_t start = m->num_objects_in_base, end;
266265
uint32_t cur_object;
@@ -274,7 +273,7 @@ static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
274273
end = m->num_objects_in_base + ntohl(m->chunk_oid_fanout[cur_fanout]);
275274

276275
for (cur_object = start; cur_object < end; cur_object++) {
277-
if ((preferred_pack > -1) &&
276+
if ((preferred_pack != NO_PREFERRED_PACK) &&
278277
(preferred_pack == nth_midxed_pack_int_id(m, cur_object))) {
279278
/*
280279
* Objects from preferred packs are added
@@ -364,7 +363,8 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
364363
preferred, cur_fanout);
365364
}
366365

367-
if (-1 < ctx->preferred_pack_idx && ctx->preferred_pack_idx < start_pack)
366+
if (ctx->preferred_pack_idx != NO_PREFERRED_PACK &&
367+
ctx->preferred_pack_idx < start_pack)
368368
midx_fanout_add_pack_fanout(&fanout, ctx->info,
369369
ctx->preferred_pack_idx, 1,
370370
cur_fanout);
@@ -843,7 +843,7 @@ static int write_midx_bitmap(struct write_midx_context *ctx,
843843
uint32_t commits_nr,
844844
unsigned flags)
845845
{
846-
int ret, i;
846+
int ret;
847847
uint16_t options = 0;
848848
struct bitmap_writer writer;
849849
struct pack_idx_entry **index;
@@ -871,7 +871,7 @@ static int write_midx_bitmap(struct write_midx_context *ctx,
871871
* this order).
872872
*/
873873
ALLOC_ARRAY(index, pdata->nr_objects);
874-
for (i = 0; i < pdata->nr_objects; i++)
874+
for (uint32_t i = 0; i < pdata->nr_objects; i++)
875875
index[i] = &pdata->objects[i].idx;
876876

877877
bitmap_writer_init(&writer, ctx->repo, pdata,
@@ -892,7 +892,7 @@ static int write_midx_bitmap(struct write_midx_context *ctx,
892892
* happens between bitmap_writer_build_type_index() and
893893
* bitmap_writer_finish().
894894
*/
895-
for (i = 0; i < pdata->nr_objects; i++)
895+
for (uint32_t i = 0; i < pdata->nr_objects; i++)
896896
index[ctx->pack_order[i]] = &pdata->objects[i].idx;
897897

898898
bitmap_writer_select_commits(&writer, commits, commits_nr);
@@ -938,39 +938,21 @@ static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
938938
return result;
939939
}
940940

941-
static int fill_packs_from_midx(struct write_midx_context *ctx,
942-
const char *preferred_pack_name, uint32_t flags)
941+
static int fill_packs_from_midx(struct write_midx_context *ctx)
943942
{
944943
struct multi_pack_index *m;
945944

946945
for (m = ctx->m; m; m = m->base_midx) {
947946
uint32_t i;
948947

949948
for (i = 0; i < m->num_packs; i++) {
950-
ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
951-
952-
/*
953-
* If generating a reverse index, need to have
954-
* packed_git's loaded to compare their
955-
* mtimes and object count.
956-
*
957-
* If a preferred pack is specified, need to
958-
* have packed_git's loaded to ensure the chosen
959-
* preferred pack has a non-zero object count.
960-
*/
961-
if (flags & MIDX_WRITE_REV_INDEX ||
962-
preferred_pack_name) {
963-
if (prepare_midx_pack(ctx->repo, m,
964-
m->num_packs_in_base + i)) {
965-
error(_("could not load pack"));
966-
return 1;
967-
}
968-
969-
if (open_pack_index(m->packs[i]))
970-
die(_("could not open index for %s"),
971-
m->packs[i]->pack_name);
949+
if (prepare_midx_pack(ctx->repo, m,
950+
m->num_packs_in_base + i)) {
951+
error(_("could not load pack"));
952+
return 1;
972953
}
973954

955+
ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
974956
fill_pack_info(&ctx->info[ctx->nr++], m->packs[i],
975957
m->pack_names[i],
976958
m->num_packs_in_base + i);
@@ -1074,11 +1056,13 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
10741056
{
10751057
struct strbuf midx_name = STRBUF_INIT;
10761058
unsigned char midx_hash[GIT_MAX_RAWSZ];
1077-
uint32_t i, start_pack;
1059+
uint32_t start_pack;
10781060
struct hashfile *f = NULL;
10791061
struct lock_file lk;
10801062
struct tempfile *incr;
1081-
struct write_midx_context ctx = { 0 };
1063+
struct write_midx_context ctx = {
1064+
.preferred_pack_idx = NO_PREFERRED_PACK,
1065+
};
10821066
int bitmapped_packs_concat_len = 0;
10831067
int pack_name_concat_len = 0;
10841068
int dropped_packs = 0;
@@ -1141,8 +1125,8 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
11411125
ctx.num_multi_pack_indexes_before++;
11421126
m = m->base_midx;
11431127
}
1144-
} else if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
1145-
flags) < 0) {
1128+
} else if (ctx.m && fill_packs_from_midx(&ctx)) {
1129+
result = 1;
11461130
goto cleanup;
11471131
}
11481132

@@ -1186,22 +1170,22 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
11861170
goto cleanup; /* nothing to do */
11871171

11881172
if (preferred_pack_name) {
1189-
ctx.preferred_pack_idx = -1;
1173+
ctx.preferred_pack_idx = NO_PREFERRED_PACK;
11901174

1191-
for (i = 0; i < ctx.nr; i++) {
1175+
for (size_t i = 0; i < ctx.nr; i++) {
11921176
if (!cmp_idx_or_pack_name(preferred_pack_name,
11931177
ctx.info[i].pack_name)) {
11941178
ctx.preferred_pack_idx = i;
11951179
break;
11961180
}
11971181
}
11981182

1199-
if (ctx.preferred_pack_idx == -1)
1183+
if (ctx.preferred_pack_idx == NO_PREFERRED_PACK)
12001184
warning(_("unknown preferred pack: '%s'"),
12011185
preferred_pack_name);
12021186
} else if (ctx.nr &&
12031187
(flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
1204-
struct packed_git *oldest = ctx.info[ctx.preferred_pack_idx].p;
1188+
struct packed_git *oldest = ctx.info[0].p;
12051189
ctx.preferred_pack_idx = 0;
12061190

12071191
if (packs_to_drop && packs_to_drop->nr)
@@ -1213,7 +1197,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
12131197
* pack-order has all of its objects selected from that pack
12141198
* (and not another pack containing a duplicate)
12151199
*/
1216-
for (i = 1; i < ctx.nr; i++) {
1200+
for (size_t i = 1; i < ctx.nr; i++) {
12171201
struct packed_git *p = ctx.info[i].p;
12181202

12191203
if (!oldest->num_objects || p->mtime < oldest->mtime) {
@@ -1229,18 +1213,23 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
12291213
* objects to resolve, so the preferred value doesn't
12301214
* matter.
12311215
*/
1232-
ctx.preferred_pack_idx = -1;
1216+
ctx.preferred_pack_idx = NO_PREFERRED_PACK;
12331217
}
12341218
} else {
12351219
/*
12361220
* otherwise don't mark any pack as preferred to avoid
12371221
* interfering with expiration logic below
12381222
*/
1239-
ctx.preferred_pack_idx = -1;
1223+
ctx.preferred_pack_idx = NO_PREFERRED_PACK;
12401224
}
12411225

1242-
if (ctx.preferred_pack_idx > -1) {
1226+
if (ctx.preferred_pack_idx != NO_PREFERRED_PACK) {
12431227
struct packed_git *preferred = ctx.info[ctx.preferred_pack_idx].p;
1228+
1229+
if (open_pack_index(preferred))
1230+
die(_("failed to open preferred pack %s"),
1231+
ctx.info[ctx.preferred_pack_idx].pack_name);
1232+
12441233
if (!preferred->num_objects) {
12451234
error(_("cannot select preferred pack %s with no objects"),
12461235
preferred->pack_name);
@@ -1252,7 +1241,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
12521241
compute_sorted_entries(&ctx, start_pack);
12531242

12541243
ctx.large_offsets_needed = 0;
1255-
for (i = 0; i < ctx.entries_nr; i++) {
1244+
for (size_t i = 0; i < ctx.entries_nr; i++) {
12561245
if (ctx.entries[i].offset > 0x7fffffff)
12571246
ctx.num_large_offsets++;
12581247
if (ctx.entries[i].offset > 0xffffffff)
@@ -1262,10 +1251,10 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
12621251
QSORT(ctx.info, ctx.nr, pack_info_compare);
12631252

12641253
if (packs_to_drop && packs_to_drop->nr) {
1265-
int drop_index = 0;
1254+
size_t drop_index = 0;
12661255
int missing_drops = 0;
12671256

1268-
for (i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
1257+
for (size_t i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
12691258
int cmp = strcmp(ctx.info[i].pack_name,
12701259
packs_to_drop->items[drop_index].string);
12711260

@@ -1296,7 +1285,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
12961285
* pack_perm[old_id] = new_id
12971286
*/
12981287
ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
1299-
for (i = 0; i < ctx.nr; i++) {
1288+
for (size_t i = 0; i < ctx.nr; i++) {
13001289
if (ctx.info[i].expired) {
13011290
dropped_packs++;
13021291
ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
@@ -1305,7 +1294,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
13051294
}
13061295
}
13071296

1308-
for (i = 0; i < ctx.nr; i++) {
1297+
for (size_t i = 0; i < ctx.nr; i++) {
13091298
if (ctx.info[i].expired)
13101299
continue;
13111300
pack_name_concat_len += strlen(ctx.info[i].pack_name) + 1;
@@ -1352,13 +1341,15 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
13521341
incr = mks_tempfile_m(midx_name.buf, 0444);
13531342
if (!incr) {
13541343
error(_("unable to create temporary MIDX layer"));
1355-
return -1;
1344+
result = -1;
1345+
goto cleanup;
13561346
}
13571347

13581348
if (adjust_shared_perm(r, get_tempfile_path(incr))) {
13591349
error(_("unable to adjust shared permissions for '%s'"),
13601350
get_tempfile_path(incr));
1361-
return -1;
1351+
result = -1;
1352+
goto cleanup;
13621353
}
13631354

13641355
f = hashfd(r->hash_algo, get_tempfile_fd(incr),
@@ -1449,6 +1440,9 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
14491440
* have been freed in the previous if block.
14501441
*/
14511442

1443+
if (ctx.num_multi_pack_indexes_before == UINT32_MAX)
1444+
die("too many multi-pack-indexes");
1445+
14521446
CALLOC_ARRAY(keep_hashes, ctx.num_multi_pack_indexes_before + 1);
14531447

14541448
if (ctx.incremental) {
@@ -1458,34 +1452,38 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
14581452

14591453
if (!chainf) {
14601454
error_errno(_("unable to open multi-pack-index chain file"));
1461-
return -1;
1455+
result = -1;
1456+
goto cleanup;
14621457
}
14631458

1464-
if (link_midx_to_chain(ctx.base_midx) < 0)
1465-
return -1;
1459+
if (link_midx_to_chain(ctx.base_midx) < 0) {
1460+
result = -1;
1461+
goto cleanup;
1462+
}
14661463

14671464
get_split_midx_filename_ext(r->hash_algo, &final_midx_name,
14681465
object_dir, midx_hash, MIDX_EXT_MIDX);
14691466

14701467
if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
14711468
error_errno(_("unable to rename new multi-pack-index layer"));
1472-
return -1;
1469+
result = -1;
1470+
goto cleanup;
14731471
}
14741472

14751473
strbuf_release(&final_midx_name);
14761474

14771475
keep_hashes[ctx.num_multi_pack_indexes_before] =
14781476
xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo));
14791477

1480-
for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
1478+
for (uint32_t i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
14811479
uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
14821480

14831481
keep_hashes[j] = xstrdup(hash_to_hex_algop(get_midx_checksum(m),
14841482
r->hash_algo));
14851483
m = m->base_midx;
14861484
}
14871485

1488-
for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
1486+
for (uint32_t i = 0; i <= ctx.num_multi_pack_indexes_before; i++)
14891487
fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]);
14901488
} else {
14911489
keep_hashes[ctx.num_multi_pack_indexes_before] =
@@ -1503,7 +1501,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
15031501
ctx.incremental);
15041502

15051503
cleanup:
1506-
for (i = 0; i < ctx.nr; i++) {
1504+
for (size_t i = 0; i < ctx.nr; i++) {
15071505
if (ctx.info[i].p) {
15081506
close_pack(ctx.info[i].p);
15091507
free(ctx.info[i].p);
@@ -1516,7 +1514,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
15161514
free(ctx.pack_perm);
15171515
free(ctx.pack_order);
15181516
if (keep_hashes) {
1519-
for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
1517+
for (uint32_t i = 0; i <= ctx.num_multi_pack_indexes_before; i++)
15201518
free((char *)keep_hashes[i]);
15211519
free(keep_hashes);
15221520
}

t/t5319-multi-pack-index.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,23 @@ test_expect_success 'repack --batch-size=0 repacks everything' '
989989
)
990990
'
991991

992+
test_expect_success EXPENSIVE 'repack/expire with many packs' '
993+
cp -r dup many &&
994+
(
995+
cd many &&
996+
997+
for i in $(test_seq 1 100)
998+
do
999+
test_commit extra$i &&
1000+
git maintenance run --task=loose-objects || return 1
1001+
done &&
1002+
1003+
git multi-pack-index write &&
1004+
git multi-pack-index repack &&
1005+
git multi-pack-index expire
1006+
)
1007+
'
1008+
9921009
test_expect_success 'repack --batch-size=<large> repacks everything' '
9931010
(
9941011
cd dup2 &&

0 commit comments

Comments
 (0)