Skip to content

Commit 6969db9

Browse files
committed
replay: fail gracefully when a merge input is unreadable
When objects involved in the merge cannot be read, the merge machinery will return early with result.clean = -1, and result.tree left as NULL. pick_regular_commit() tested only "if (!result->clean)", ignoring the case where "clean < 0". That causes the code to try to use result->tree, resulting in a SIGSEGV. Handle clean < 0 explicitly; the merge machinery will already have printed messages such as "Could not read <object>" and "collecting merge info failed for trees...", so we don't need to add much detail beyond the fact that the merge failed. Signed-off-by: Elijah Newren <newren@gmail.com>
1 parent 18e6685 commit 6969db9

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

‎replay.c‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,13 @@ static struct commit *pick_regular_commit(struct repository *repo,
327327
merge_opt->ancestor = NULL;
328328
merge_opt->branch2 = NULL;
329329

330+
if (result->clean < 0) {
331+
error(_("merge of %s onto %s failed"),
332+
oid_to_hex(&pickme->object.oid),
333+
oid_to_hex(&replayed_base->object.oid));
334+
return NULL;
335+
}
336+
330337
if (!result->clean)
331338
return NULL;
332339

‎t/t3650-replay-basics.sh‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,4 +565,38 @@ test_expect_success '--onto with --ref rejects multiple revision ranges' '
565565
test_grep "cannot be used with multiple revision ranges" err
566566
'
567567

568+
test_expect_success 'replay fails without segfault when objects are missing' '
569+
test_when_finished "rm -fr unreadable" &&
570+
git init unreadable &&
571+
(
572+
cd unreadable &&
573+
574+
test_write_lines l1 l2 l3 l4 l5 l6 l7 l8 >f &&
575+
git add f &&
576+
git commit -m base &&
577+
git branch base &&
578+
579+
test_write_lines l1 l2 l3 l4 l5 l6 l7 CHANGED >f &&
580+
git commit -am side &&
581+
git branch side &&
582+
583+
git switch -c onto base &&
584+
test_write_lines CHANGED l2 l3 l4 l5 l6 l7 l8 >f &&
585+
git commit -am onto &&
586+
587+
# The replay works while every object is readable.
588+
git replay --onto onto base..side &&
589+
590+
# Removing the onto tree makes parse_tree() fail during the
591+
# incore merge, driving clean < 0 with a NULL result tree.
592+
onto_tree=$(git rev-parse onto^{tree}) &&
593+
obj=$(test_oid_to_path "$onto_tree") &&
594+
mv .git/objects/${obj} saved-tree &&
595+
596+
# Ensure replay gracefully handles the missing object
597+
test_must_fail git replay --onto onto base..side 2>err &&
598+
test_grep "Could not read\|collecting merge info failed" err
599+
)
600+
'
601+
568602
test_done

0 commit comments

Comments
 (0)