Binary-file detection called buf_has_nulls on the whole buffer at
every refill, rescanning the saved leading-context bytes that were
already checked when first read.  With -B N or -C N large enough that
the saved region dwarfs the 96 KiB read size, this rescan dominated:
a matchless search of a 3.4 GB log file with -C 1000000 spent over
600 s in strlen alone, versus 5 s once only new bytes are checked.
Detection behavior is unchanged: any null byte among the saved bytes
was already detected in the iteration that read those bytes.
* src/grep.c (grep): Pass only the newly read data, which starts SAVE
bytes into the buffer, to buf_has_nulls.
* NEWS: Mention the -B/-C performance improvements.
---
 NEWS       | 9 +++++++++
 src/grep.c | 5 ++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 5049a85..29aad92 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,15 @@ GNU grep NEWS                                    -*- outline 
-*-
   On Windows platforms and on AIX in 32-bit mode, grep now fully
   supports Unicode characters outside the Basic Multilingual Plane.
 
+** Improvements
+
+  With -B N or -C N, grep no longer spends time proportional to N per
+  buffer refill and per matching line, which made large N quadratically
+  slow.  For example, searching a 3.4 GB log file for a pattern that
+  never matches took 1.3 s with -C 1 but 34 s with -C 10000; the
+  latter now takes 2.5 s.
+  [bug present since "the beginning"]
+
 
 * Noteworthy changes in release 3.12 (2025-04-10) [stable]
 
diff --git a/src/grep.c b/src/grep.c
index a5afbe5..8c1d103 100644
--- a/src/grep.c
+++ b/src/grep.c
@@ -1558,8 +1558,11 @@ grep (int fd, struct stat const *st, bool *ineof)
 
   for (bool firsttime = true; ; firsttime = false)
     {
+      /* Check only the newly read bytes for null bytes; the first SAVE
+         bytes are saved leading context and residue, already checked
+         when first read.  */
       if (nlines_first_null < 0 && eol && binary_files != TEXT_BINARY_FILES
-          && (buf_has_nulls (bufbeg, buflim - bufbeg)
+          && (buf_has_nulls (bufbeg + save, buflim - bufbeg - save)
               || (firsttime && file_must_have_nulls (buflim - bufbeg, fd, 
st))))
         {
           if (binary_files == WITHOUT_MATCH_BINARY_FILES)
-- 
2.43.0




Reply via email to