summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-01-08 16:40:11 +0900
committerJunio C Hamano <gitster@pobox.com>2026-01-08 16:40:11 +0900
commitc0754dc42305cb37823955722a5167755634c8c1 (patch)
tree4336e1485b15606f6bd05edc18eb988335e1f59a
parentd28d2be5f2aa6acbd0c86b8fbae68cd222de3f4f (diff)
parent56d388e6ad9e819935a902b6d5ce3a6b3485b6e2 (diff)
downloadgit-c0754dc42305cb37823955722a5167755634c8c1.tar.xz
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
-rw-r--r--diff.c5
-rwxr-xr-xt/t4067-diff-partial-clone.sh35
2 files changed, 40 insertions, 0 deletions
diff --git a/diff.c b/diff.c
index 436da250eb..a68ddd2168 100644
--- a/diff.c
+++ b/diff.c
@@ -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);
}
diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh
index 581250dd2d..72f25de449 100755
--- a/t/t4067-diff-partial-clone.sh
+++ b/t/t4067-diff-partial-clone.sh
@@ -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" &&