From: Tanga Joris <tangajoris@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, jackrawlings2011@gmail.com,
christian.couder@gmail.com, siddharthasthana31@gmail.com,
kaartic.sivaraam@gmail.com, usmanakinyemi202@gmail.com,
Tanga Joris <tangajoris@gmail.com>
Subject: [Outreachy PATCH 1/2] apply: do not keep names from an unused "diff --git" line
Date: Sat, 7 Nov 2026 22:54:28 +0300 [thread overview]
Message-ID: <20261107195429.96842-1-tangajoris@gmail.com> (raw)
In-Reply-To: <CALdwsC1cMKZgRPZA+pBaJe4PPs9q9W0K9CQLmM2bgUCyysTB-w@mail.gmail.com>
When a "diff --git" line is followed by a line that is not a git
header line, such as a blank line or an indented "new file mode"
line, parse_git_diff_header() stops right after the "diff --git"
line. find_header() then treats it as an empty git header and keeps
looking, as it has done since 206de27efa (git-apply: ignore empty git
headers, 2005-06-12). It finds the "--- /dev/null" and "+++ b/<path>"
lines and reads the rest as a traditional patch.
But parse_git_diff_header() has already set old_name and new_name
from the "diff --git" line. These names stay in the patch.
parse_traditional_patch() sets is_new for "--- /dev/null", but it
does not clear old_name. So "git apply --check" dies on the assertion
that 5c47f4c6e7 (builtin-apply: accept patch to an empty file,
2008-05-17) added to check_preimage():
check_preimage: Assertion `patch->is_new <= 0' failed.
The stale new_name causes the same crash when a deletion with such a
header is applied with "git apply -R". The stale names also break an
empty "diff --git" section that is followed by another section. They
do not match the names in the next section, so "git apply" fails with
a "bad git-diff" error.
Free the names when the "diff --git" line is not used. A new file is
then created, and a deletion can be reversed. An empty section is
ignored, as 206de27efa intended. As with any traditional patch, the
"new file mode" line is not used, so a new file gets the default mode.
parse_git_diff_header() has also set is_toplevel_relative. Keep it,
so that the paths stay relative to the top of the repository, as
before.
Reported-by: Gingrspacecadet <jackrawlings2011@gmail.com>
Signed-off-by: Tanga Joris <tangajoris@gmail.com>
---
This fixes the crash reported in [1]. While looking into it, I found
two more ways to trigger the same assertion: an indented "new file
mode" line, which this patch also fixes, and a "---" line before
"new file mode", which 2/2 handles. Git 2.43 crashes on all three.
I based this on maint (v2.56.0), since the crash is in released
versions. It merges cleanly with master, next and seen.
[1] https://lore.kernel.org/git/CALdwsC1cMKZgRPZA+pBaJe4PPs9q9W0K9CQLmM2bgUCyysTB-w@mail.gmail.com/
apply.c | 10 ++++-
t/t4133-apply-filenames.sh | 90 ++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/apply.c b/apply.c
index f00b7ba4d3..b56b363963 100644
--- a/apply.c
+++ b/apply.c
@@ -1651,8 +1651,16 @@ static int find_header(struct apply_state *state,
size, patch);
if (git_hdr_len < 0)
return -128;
- if (git_hdr_len <= len)
+ if (git_hdr_len <= len) {
+ /*
+ * Not a git header after all. Do not keep the
+ * names it took from the "diff --git" line.
+ */
+ FREE_AND_NULL(patch->def_name);
+ FREE_AND_NULL(patch->old_name);
+ FREE_AND_NULL(patch->new_name);
continue;
+ }
*hdrsize = git_hdr_len;
return offset;
}
diff --git a/t/t4133-apply-filenames.sh b/t/t4133-apply-filenames.sh
index 3cab1038cf..727c36e7ea 100755
--- a/t/t4133-apply-filenames.sh
+++ b/t/t4133-apply-filenames.sh
@@ -60,4 +60,94 @@ test_expect_success 'apply diff with old filename missing from headers' '
test_grep "lacks filename information" err
'
+test_expect_success 'apply new file with a blank line after "diff --git"' '
+ test_when_finished "rm -f f" &&
+ cat >blank_line.diff <<-\EOF &&
+ diff --git a/f b/f
+
+ new file mode 100644
+ index 0000000..d00491f
+ --- /dev/null
+ +++ b/f
+ @@ -0,0 +1 @@
+ +1
+ EOF
+ git apply --check blank_line.diff &&
+ git apply blank_line.diff &&
+ echo 1 >expect &&
+ test_cmp expect f
+'
+
+test_expect_success 'apply new file with an indented "new file mode" line' '
+ test_when_finished "rm -f f" &&
+ cat >indented_mode.diff <<-\EOF &&
+ diff --git a/f b/f
+ new file mode 100644
+ index 0000000..d00491f
+ --- /dev/null
+ +++ b/f
+ @@ -0,0 +1 @@
+ +1
+ EOF
+ git apply --check indented_mode.diff &&
+ git apply indented_mode.diff &&
+ echo 1 >expect &&
+ test_cmp expect f
+'
+
+test_expect_success 'reverse a deletion with a blank line after "diff --git"' '
+ test_when_finished "rm -f f" &&
+ cat >blank_line_delete.diff <<-\EOF &&
+ diff --git a/f b/f
+
+ deleted file mode 100644
+ index d00491f..0000000
+ --- a/f
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -1
+ EOF
+ git apply -R --check blank_line_delete.diff &&
+ git apply -R blank_line_delete.diff &&
+ echo 1 >expect &&
+ test_cmp expect f
+'
+
+test_expect_success 'ignore an empty "diff --git" section' '
+ test_when_finished "rm -f g" &&
+ echo 1 >g &&
+ cat >empty_section.diff <<-\EOF &&
+ diff --git a/f b/f
+ diff --git a/g b/g
+ index d00491f..0cfbf08 100644
+ --- a/g
+ +++ b/g
+ @@ -1 +1 @@
+ -1
+ +2
+ EOF
+ git apply --check empty_section.diff &&
+ git apply empty_section.diff &&
+ echo 2 >expect &&
+ test_cmp expect g
+'
+
+test_expect_success 'blank line after "diff --git" keeps paths relative to the top' '
+ test_when_finished "rm -rf sub" &&
+ mkdir sub &&
+ cat >sub/blank_line.diff <<-\EOF &&
+ diff --git a/f b/f
+
+ new file mode 100644
+ index 0000000..d00491f
+ --- /dev/null
+ +++ b/f
+ @@ -0,0 +1 @@
+ +1
+ EOF
+ git -C sub apply blank_line.diff &&
+ test_path_is_missing sub/f &&
+ test_path_is_missing f
+'
+
test_done
base-commit: a018953688f1b10bddf91bff8747068f5f4746a4
--
2.43.0
next prev parent reply other threads:[~2026-11-07 19:55 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-17 15:17 Git crashed on `git apply --check` Gingrspacecadet
2026-10-24 6:10 ` Tanga Joris
[not found] ` <CALdwsC11JHUBBTt3e_RFixLYSF0VU1C+mG7bQsO0vV=a68XHNw@mail.gmail.com>
2026-10-25 22:56 ` Tanga Joris
2026-11-07 19:54 ` Tanga Joris [this message]
2026-11-07 19:54 ` [Outreachy PATCH 2/2] apply: reject new and deleted files that have both names Tanga Joris
2026-11-09 10:52 ` [Outreachy PATCH 1/2] apply: do not keep names from an unused "diff --git" line Phillip Wood
2026-11-09 13:13 ` Tanga Joris
2026-11-09 14:31 ` Phillip Wood
2026-11-09 20:54 ` Tanga Joris
2026-11-09 21:06 ` Junio C Hamano
2026-11-09 23:03 ` Tanga Joris
2026-11-09 19:56 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261107195429.96842-1-tangajoris@gmail.com \
--to=tangajoris@gmail.com \
--cc=christian.couder@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jackrawlings2011@gmail.com \
--cc=kaartic.sivaraam@gmail.com \
--cc=siddharthasthana31@gmail.com \
--cc=usmanakinyemi202@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox