Merge branch 'ds/diff-lazy-fetch-with-name-only-fix'

Running "git diff" with "--name-only" and other options that allows
us not to look at the blob contents, while objects that are lazily
fetched from a promisor remote, caused use-after-free, which has
been corrected.

* ds/diff-lazy-fetch-with-name-only-fix:
  diff: avoid segfault with freed entries
This commit is contained in:
Junio C Hamano 2026-01-08 16:40:11 +09:00
commit c0754dc423
2 changed files with 40 additions and 0 deletions

5
diff.c
View File

@ -7098,6 +7098,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
if (!diffopt->flags.no_index)
diffopt->skip_stat_unmatch++;
diff_free_filepair(p);
q->queue[i] = NULL;
}
}
free(q->queue);
@ -7141,6 +7142,10 @@ void diff_queued_diff_prefetch(void *repository)
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (!p)
continue;
diff_add_if_missing(repo, &to_fetch, p->one);
diff_add_if_missing(repo, &to_fetch, p->two);
}

View File

@ -132,6 +132,41 @@ test_expect_success 'diff with rename detection batches blobs' '
test_line_count = 1 done_lines
'
test_expect_success 'diff succeeds even if entries are removed from queue' '
test_when_finished "rm -rf server client trace" &&
test_create_repo server &&
for l in a c e g i p
do
echo $l >server/$l &&
git -C server add $l || return 1
done &&
git -C server commit -m x &&
for l in a e i
do
git -C server rm $l || return 1
done &&
for l in b d f i
do
echo $l$l >server/$l &&
git -C server add $l || return 1
done &&
git -C server commit -a -m x &&
test_config -C server uploadpack.allowfilter 1 &&
test_config -C server uploadpack.allowanysha1inwant 1 &&
git clone --filter=blob:limit=0 "file://$(pwd)/server" client &&
for file in $(ls client)
do
cat client/$file >$file &&
mv $file client/$file || return 1
done &&
git -C client diff --name-only --relative HEAD^
'
test_expect_success 'diff does not fetch anything if inexact rename detection is not needed' '
test_when_finished "rm -rf server client trace" &&