git: f97b6a8f84b3 - main - patch: fix pch_context() for unified diffs with no leading context

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Fri, 29 Aug 2025 19:24:56 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=f97b6a8f84b3ed209c2aea0958a7b889d0bf27ed

commit f97b6a8f84b3ed209c2aea0958a7b889d0bf27ed
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-08-29 19:24:35 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2025-08-29 19:24:35 +0000

    patch: fix pch_context() for unified diffs with no leading context
    
    When the first line of a file is a removal, we may not have any leading
    context.  Only adjusting p_context if context > 0 means that we
    incorrectly believe that we have 100 lines of context when the reality
    is that we have none.
    
    This fixes a bug with fuzz-checking, which ends up fuzzing away the line
    we're trying to replace if it's the first line in the file.  We use
    pch_context() to determine a reasonable max-fuzz.
    
    PR:             250511
    Reviewed by:    pfg
    Differential Revision:  https://reviews.freebsd.org/D51837
---
 usr.bin/patch/pch.c                       |  2 +-
 usr.bin/patch/tests/unified_patch_test.sh | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/usr.bin/patch/pch.c b/usr.bin/patch/pch.c
index 71f73125a8cb..9bc4599026ae 100644
--- a/usr.bin/patch/pch.c
+++ b/usr.bin/patch/pch.c
@@ -1054,7 +1054,7 @@ hunk_done:
 				p_end = fillnew;
 				malformed();
 			}
-			if (ch != ' ' && context > 0) {
+			if (ch != ' ' && context >= 0) {
 				if (context < p_context)
 					p_context = context;
 				context = -1000;
diff --git a/usr.bin/patch/tests/unified_patch_test.sh b/usr.bin/patch/tests/unified_patch_test.sh
index 7d4b74182c41..47c4dc5faf73 100755
--- a/usr.bin/patch/tests/unified_patch_test.sh
+++ b/usr.bin/patch/tests/unified_patch_test.sh
@@ -25,6 +25,26 @@
 # SUCH DAMAGE.
 #
 
+atf_test_case badfuzz
+badfuzz_head()
+{
+	atf_set "descr" "Test for patch(1) erroneously fuzzing away action lines"
+}
+badfuzz_body()
+{
+	# PR 250511 demonstrates a scenario where patch(1) will happily apply a
+	# patch into the wrong location if we have some lines that are still
+	# similar in the trailing context.  In the following example, it would
+	# actually replace the underscore before the second series of B\nC\nO
+	# with "Z", when the patch should have been rejected instead.
+	printf "A\nB\nC\nO\n_\nB\nC\nO\n" > file.orig
+	printf "Z\nB\nC\nO\n_\nB\nC\nO\n" > file
+	printf "OK\nDIFF1\nDIFF2\n\n_\nB\nC\nO\n" > file.newer
+
+	atf_check -s not-exit:0 -o save:file.patch diff -u3 file.orig file
+	atf_check -s not-exit:0 -o not-empty patch file.newer file.patch
+}
+
 atf_test_case basic
 basic_body()
 {
@@ -161,6 +181,7 @@ EOF
 
 atf_init_test_cases()
 {
+	atf_add_test_case badfuzz
 	atf_add_test_case basic
 	atf_add_test_case limited_ctx
 	atf_add_test_case file_creation