diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2015-02-10 23:44:36 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2015-02-10 23:46:12 -0800 |
commit | fbc60d437bcaa586801441677bb1dccc1f7077d8 (patch) | |
tree | c66596c9f81d4dcb7e3868262ca73c7c967c3084 /src/pcresearch.c | |
parent | 846e7eee8bdc84b332150043a66fe8f17dc1a30b (diff) | |
download | grep-fbc60d437bcaa586801441677bb1dccc1f7077d8.tar.gz |
Grow the JIT stack if it becomes exhausted
Problem reported by Oliver Freyermuth in: http://bugs.gnu.org/19833
* NEWS: Document the fix.
* tests/Makefile.am (TESTS): Add pcre-jitstack.
* tests/pcre-jitstack: New file.
* src/pcresearch.c (NSUB): Move decl earlier, since it's needed
earlier now.
(jit_stack_size) [PCRE_STUDY_JIT_COMPILE]: New static var.
(jit_exec): New function.
(Pcompile): Initialize jit_stack_size.
(Pexecute): Use new jit_exec function. Report a useful diagnostic
if the error is PCRE_ERROR_JIT_STACKLIMIT.
Diffstat (limited to 'src/pcresearch.c')
-rw-r--r-- | src/pcresearch.c | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/src/pcresearch.c b/src/pcresearch.c index 0bd021aa..afe4f2bd 100644 --- a/src/pcresearch.c +++ b/src/pcresearch.c @@ -27,6 +27,11 @@ #endif #if HAVE_LIBPCRE + +/* This must be at least 2; everything after that is for performance + in pcre_exec. */ +enum { NSUB = 300 }; + /* Compiled internal form of a Perl regular expression. */ static pcre *cre; @@ -36,6 +41,45 @@ static pcre_extra *extra; # ifndef PCRE_STUDY_JIT_COMPILE # define PCRE_STUDY_JIT_COMPILE 0 # endif + +# if PCRE_STUDY_JIT_COMPILE +/* Maximum size of the JIT stack. */ +static int jit_stack_size; +# endif + +/* Match the already-compiled PCRE pattern against the data in P, of + size SEARCH_BYTES, with options OPTIONS, and storing resulting + matches into SUB. Return the (nonnegative) match location or a + (negative) error number. */ +static int +jit_exec (char const *p, int search_bytes, int options, int *sub) +{ + while (true) + { + int e = pcre_exec (cre, extra, p, search_bytes, 0, options, sub, NSUB); + +# if PCRE_STUDY_JIT_COMPILE + if (e == PCRE_ERROR_JIT_STACKLIMIT + && 0 < jit_stack_size && jit_stack_size <= INT_MAX / 2) + { + int old_size = jit_stack_size; + int new_size = jit_stack_size = old_size * 2; + static pcre_jit_stack *jit_stack; + if (jit_stack) + pcre_jit_stack_free (jit_stack); + jit_stack = pcre_jit_stack_alloc (old_size, new_size); + if (!jit_stack) + error (EXIT_TROUBLE, 0, + _("failed to allocate memory for the PCRE JIT stack")); + pcre_assign_jit_stack (extra, NULL, jit_stack); + continue; + } +# endif + + return e; + } +} + #endif #if HAVE_LIBPCRE @@ -44,10 +88,6 @@ static pcre_extra *extra; static int empty_match[2]; #endif -/* This must be at least 2; everything after that is for performance - in pcre_exec. */ -enum { NSUB = 300 }; - void Pcompile (char const *pattern, size_t size) { @@ -121,19 +161,11 @@ Pcompile (char const *pattern, size_t size) if (pcre_fullinfo (cre, extra, PCRE_INFO_JIT, &e)) error (EXIT_TROUBLE, 0, _("internal error (should never happen)")); + /* The PCRE documentation says that a 32 KiB stack is the default. */ if (e) - { - /* A 32K stack is allocated for the machine code by default, which - can grow to 512K if necessary. Since JIT uses far less memory - than the interpreter, this should be enough in practice. */ - pcre_jit_stack *jit_stack = pcre_jit_stack_alloc (32 * 1024, 512 * 1024); - if (!jit_stack) - error (EXIT_TROUBLE, 0, - _("failed to allocate memory for the PCRE JIT stack")); - pcre_assign_jit_stack (extra, NULL, jit_stack); - } - + jit_stack_size = 32 << 10; # endif + free (re); int sub[NSUB]; @@ -214,8 +246,7 @@ Pexecute (char const *buf, size_t size, size_t *match_size, if (multiline) options |= PCRE_NO_UTF8_CHECK; - e = pcre_exec (cre, extra, p, search_bytes, 0, - options, sub, NSUB); + e = jit_exec (p, search_bytes, options, sub); if (e != PCRE_ERROR_BADUTF8) { if (0 < e && multiline && sub[1] - sub[0] != 0) @@ -268,9 +299,13 @@ Pexecute (char const *buf, size_t size, size_t *match_size, case PCRE_ERROR_NOMEMORY: error (EXIT_TROUBLE, 0, _("memory exhausted")); +# if PCRE_STUDY_JIT_COMPILE + case PCRE_ERROR_JIT_STACKLIMIT: + error (EXIT_TROUBLE, 0, _("PCRE JIT stack exhausted")); +# endif + case PCRE_ERROR_MATCHLIMIT: - error (EXIT_TROUBLE, 0, - _("exceeded PCRE's backtracking limit")); + error (EXIT_TROUBLE, 0, _("exceeded PCRE's backtracking limit")); default: /* For now, we lump all remaining PCRE failures into this basket. |