Subject: Re: [bug-diffutils] bug#18402: Wrong output for single character files without newline
From: Paul Eggert <[email-masked]>
To: Eric Blake <[email-masked]>, [email-masked], Matt Johnson <[email-masked]>, [email-masked]
Date: Wed, 03 Sep 2014 16:05:55 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Thanks for reporting that.  I installed the attached 3 patches; patch #2 
should fix the bug.
From 7bdd6479ce43d6b45803fd0bc4b363370975ceab Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Wed, 3 Sep 2014 15:25:21 -0700
Subject: [PATCH 1/3] diff: fix performance bug with prefix computation

* src/io.c (find_identical_ends): Fix performance bug:
the test for when the prefix was needed messed up by
the 2002-02-28 integer-overflow fixes, causing performance to be
worse than it needed to be.
---
 src/io.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/io.c b/src/io.c
index 05a898c..1a8b936 100644
--- a/src/io.c
+++ b/src/io.c
@@ -538,6 +538,7 @@ find_identical_ends (struct file_data filevec[])
   lin i, lines;
   size_t n0, n1;
   lin alloc_lines0, alloc_lines1;
+  bool prefix_needed;
   lin buffered_prefix, prefix_count, prefix_mask;
   lin middle_guess, suffix_guess;
 
@@ -687,12 +688,13 @@ find_identical_ends (struct file_data filevec[])
   prefix_mask = prefix_count - 1;
   lines = 0;
   linbuf0 = xmalloc (alloc_lines0 * sizeof *linbuf0);
+  prefix_needed = ! (no_diff_means_no_output
+		     && filevec[0].prefix_end == p0
+		     && filevec[1].prefix_end == p1);
   p0 = buffer0;
 
   /* If the prefix is needed, find the prefix lines.  */
-  if (! (no_diff_means_no_output
-	 && filevec[0].prefix_end == p0
-	 && filevec[1].prefix_end == p1))
+  if (prefix_needed)
     {
       end0 = filevec[0].prefix_end;
       while (p0 != end0)
-- 
1.9.3

From d2fd9d4683ef60c259a3b426f71cef1b89ff383d Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Wed, 3 Sep 2014 15:58:03 -0700
Subject: [PATCH 2/3] diff: fix bug with diff -B and incomplete lines

Reported by Navin Kabra via Eric Blake in:
http://bugs.gnu.org/18402
* src/util.c (analyze_hunk): Don't mishandle incomplete
lines at end of file.
* tests/no-newline-at-eof: Test for the bug.
---
 src/util.c              | 6 ++++--
 tests/no-newline-at-eof | 6 ++++++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/util.c b/src/util.c
index 016057d..44ce61f 100644
--- a/src/util.c
+++ b/src/util.c
@@ -817,7 +817,8 @@ analyze_hunk (struct change *hunk,
       for (i = next->line0; i <= l0 && trivial; i++)
 	{
 	  char const *line = linbuf0[i];
-	  char const *newline = linbuf0[i + 1] - 1;
+	  char const *lastbyte = linbuf0[i + 1] - 1;
+	  char const *newline = lastbyte + (*lastbyte != '\n');
 	  size_t len = newline - line;
 	  char const *p = line;
 	  if (skip_white_space)
@@ -837,7 +838,8 @@ analyze_hunk (struct change *hunk,
       for (i = next->line1; i <= l1 && trivial; i++)
 	{
 	  char const *line = linbuf1[i];
-	  char const *newline = linbuf1[i + 1] - 1;
+	  char const *lastbyte = linbuf1[i + 1] - 1;
+	  char const *newline = lastbyte + (*lastbyte != '\n');
 	  size_t len = newline - line;
 	  char const *p = line;
 	  if (skip_white_space)
diff --git a/tests/no-newline-at-eof b/tests/no-newline-at-eof
index 14d5f49..f503718 100755
--- a/tests/no-newline-at-eof
+++ b/tests/no-newline-at-eof
@@ -50,4 +50,10 @@ compare exp2 out || fail=1
 # expect empty stderr
 compare /dev/null err || fail=1
 
+# Test for Bug#18402.
+printf a > a
+printf b > b
+diff -B a b > out 2>err
+test $? = 1 || fail=1
+
 Exit $fail
-- 
1.9.3

From df3af29627a92495a740da13cb8bb0d4fcc1bf84 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Wed, 3 Sep 2014 16:02:35 -0700
Subject: [PATCH 3/3] doc: mention diff -B fix in NEWS

---
 NEWS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/NEWS b/NEWS
index 58a7cbb..9f388dd 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,9 @@ GNU diffutils NEWS                                    -*- outline -*-
   consider two Asian file names to be the same merely because they
   contain no English characters.
 
+  diff -B no longer generates incorrect output if the two inputs
+  each end with a one-byte incomplete line.
+
 ** Performance changes
 
   diff's default algorithm has been adjusted to output higher-quality
-- 
1.9.3