Subject: Re: GNU grep 3.1 fails test suite when PCRE lacks JIT

From: Paul Eggert <[email-masked]>
Date: Wed, 9 Sep 2020 16:10:41 -0700

On 1/2/20 1:47 PM, Thomas Deutschmann wrote:

> I managed to reproduce the error using pure Debian:

Thanks, with that recipe I reproduced the problem on Ubuntu 18.04.5, and 
installed the attached. I'll boldly close the bug report.

libpcre is quite a pain to use, and makes 'grep' less reliable. Perhaps somebody 
with some time could see whether libpcre2 is any better.
From 51f5e2d509e1ca4863ecc93a153366b02f51d647 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Wed, 9 Sep 2020 14:09:54 -0700
Subject: [PATCH 1/2] grep: fix PCRE JIT test when JIT not available

Problem reported by Thomas Deutschmann (Bug#29446#23).
* src/pcresearch.c (Pexecute): Diagnose PCRE_ERROR_RECURSIONLIMIT.
* tests/pcre-jitstack: Treat recursion limit overflow like stack
overflow.
---
 src/pcresearch.c    | 3 +++
 tests/pcre-jitstack | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/pcresearch.c b/src/pcresearch.c
index 2fcbf8e..e265083 100644
--- a/src/pcresearch.c
+++ b/src/pcresearch.c
@@ -311,6 +311,9 @@ Pexecute (void *vcp, char const *buf, size_t size, size_t *match_size,
         case PCRE_ERROR_MATCHLIMIT:
           die (EXIT_TROUBLE, 0, _("exceeded PCRE's backtracking limit"));
 
+        case PCRE_ERROR_RECURSIONLIMIT:
+          die (EXIT_TROUBLE, 0, _("exceeded PCRE's recursion limit"));
+
         default:
           /* For now, we lump all remaining PCRE failures into this basket.
              If anyone cares to provide sample grep usage that can trigger
diff --git a/tests/pcre-jitstack b/tests/pcre-jitstack
index d5a621b..39cda92 100755
--- a/tests/pcre-jitstack
+++ b/tests/pcre-jitstack
@@ -56,7 +56,8 @@ if test $? != 1; then
        || fail=1
 
     # If that failed due to stack overflow, don't cry foul.
-    test $fail = 1 && { grep -q 'stack overflow' err && fail=0 || cat err; }
+    overflow_pat="stack overflow|exceeded PCRE's recursion limit"
+    test $fail = 1 && { grep -Eq "$overflow_pat" err && fail=0 || cat err; }
 fi
 
 Exit $fail
-- 
2.17.1

From 87dc91f5cf2c748d834dbff7b250a153c762387d Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Wed, 9 Sep 2020 15:07:01 -0700
Subject: [PATCH 2/2] grep: fix logic for growing PCRE JIT stack

* src/pcresearch.c (jit_exec) [PCRE_EXTRA_MATCH_LIMIT_RECURSION]:
When growing the match_limit_recursion limit, do not use the old
value if ! (flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION), as it is
uninitialized in that case.
---
 src/pcresearch.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/pcresearch.c b/src/pcresearch.c
index e265083..a668c45 100644
--- a/src/pcresearch.c
+++ b/src/pcresearch.c
@@ -90,16 +90,18 @@ jit_exec (struct pcre_comp *pc, char const *subject, int search_bytes,
 
 #if PCRE_EXTRA_MATCH_LIMIT_RECURSION
       if (e == PCRE_ERROR_RECURSIONLIMIT
-          && (PCRE_STUDY_EXTRA_NEEDED || pc->extra)
-          && pc->extra->match_limit_recursion <= ULONG_MAX / 2)
+          && (PCRE_STUDY_EXTRA_NEEDED || pc->extra))
         {
-          pc->extra->match_limit_recursion *= 2;
-          if (pc->extra->match_limit_recursion == 0)
+          unsigned long lim
+            = (pc->extra->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION
+               ? pc->extra->match_limit_recursion
+               : 0);
+          if (lim <= ULONG_MAX / 2)
             {
-              pc->extra->match_limit_recursion = (1 << 24) - 1;
+              pc->extra->match_limit_recursion = lim ? 2 * lim : (1 << 24) - 1;
               pc->extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
+              continue;
             }
-          continue;
         }
 #endif
 
-- 
2.17.1