PCRE1 allowed for a compile time flag to disable JIT, but PCRE2 never
had one, forcing the use of JIT if -P was requested.

After ed0479ce3d (Merge branch 'ab/no-kwset' into next, 2019-07-15)
the PCRE2 engine will be used more broadly and therefore adding this
knob will allow users a escape from situations where JIT might be
problematic.

JIT will be used by default but it can be disabled with the --no-pcre-jit
option in `git grep` or by setting 0/false into the pcre.jit config.

If a value of -1 is used instead then the following error is prevented by
using the interpreter when a JIT failure consistent with known security
restrictions is found at regex compilation time.

  $ git grep 'foo bar'
  fatal: Couldn't JIT the PCRE2 pattern 'foo bar', got '-48'

Signed-off-by: Carlo Marcelo Arenas Belón <care...@gmail.com>
---
V2: add command line to grep as suggested by Junio

 Documentation/git-grep.txt | 11 +++++++++++
 builtin/grep.c             |  4 ++++
 grep.c                     | 30 ++++++++++++++++++++++++++----
 grep.h                     |  1 +
 4 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index c89fb569e3..895c6b34ec 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -13,6 +13,7 @@ SYNOPSIS
           [-v | --invert-match] [-h|-H] [--full-name]
           [-E | --extended-regexp] [-G | --basic-regexp]
           [-P | --perl-regexp]
+          [-j | --[no]-pcre-jit]
           [-F | --fixed-strings] [-n | --line-number] [--column]
           [-l | --files-with-matches] [-L | --files-without-match]
           [(-O | --open-files-in-pager) [<pager>]]
@@ -69,6 +70,12 @@ grep.fallbackToNoIndex::
        If set to true, fall back to git grep --no-index if git grep
        is executed outside of a git repository.  Defaults to false.
 
+pcre.jit::
+       If set to false, disable JIT when using PCRE.  Defaults to
+       true.
+       if set to -1 will try first to use JIT and fallback to the
+       interpreter instead of returning an error.
+
 
 OPTIONS
 -------
@@ -175,6 +182,10 @@ providing this option will cause it to die.
        Use fixed strings for patterns (don't interpret pattern
        as a regex).
 
+-j::
+--[no-]pcre-jit::
+       Diable JIT in PCRE with --no-pcre-jit.
+
 -n::
 --line-number::
        Prefix the line number to matching lines.
diff --git a/builtin/grep.c b/builtin/grep.c
index 580fd38f41..b0e94875b2 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -923,6 +923,10 @@ int cmd_grep(int argc, const char **argv, const char 
*prefix)
                OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored,
                           N_("allow calling of grep(1) (ignored by this 
build)"),
                           PARSE_OPT_NOCOMPLETE),
+               OPT_GROUP("PCRE"),
+               OPT_SET_INT('j', "pcre-jit", &opt.pcre_jit,
+                       N_("when to use JIT with PCRE"),
+                       1),
                OPT_END()
        };
 
diff --git a/grep.c b/grep.c
index c7c06ae08d..d58cad0257 100644
--- a/grep.c
+++ b/grep.c
@@ -56,6 +56,7 @@ void init_grep_defaults(struct repository *repo)
        opt->repo = repo;
        opt->relative = 1;
        opt->pathname = 1;
+       opt->pcre_jit = 1;
        opt->max_depth = -1;
        opt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
        color_set(opt->colors[GREP_COLOR_CONTEXT], "");
@@ -125,6 +126,12 @@ int grep_config(const char *var, const char *value, void 
*cb)
                return 0;
        }
 
+       if (!strcmp(var, "pcre.jit")) {
+               int is_bool;
+               opt->pcre_jit = git_config_bool_or_int(var, value, &is_bool);
+               return 0;
+       }
+
        if (!strcmp(var, "color.grep"))
                opt->color = git_config_colorbool(var, value);
        if (!strcmp(var, "color.grep.match")) {
@@ -163,6 +170,7 @@ void grep_init(struct grep_opt *opt, struct repository 
*repo, const char *prefix
        opt->pattern_tail = &opt->pattern_list;
        opt->header_tail = &opt->header_list;
 
+       opt->pcre_jit = def->pcre_jit;
        opt->only_matching = def->only_matching;
        opt->color = def->color;
        opt->extended_regexp_option = def->extended_regexp_option;
@@ -393,7 +401,8 @@ static void compile_pcre1_regexp(struct grep_pat *p, const 
struct grep_opt *opt)
                die("%s", error);
 
 #ifdef GIT_PCRE1_USE_JIT
-       pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
+       if (opt->pcre_jit)
+               pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
 #endif
 }
 
@@ -489,11 +498,24 @@ static void compile_pcre2_pattern(struct grep_pat *p, 
const struct grep_opt *opt
                compile_regexp_failed(p, (const char *)&errbuf);
        }
 
-       pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
+       if (opt->pcre_jit)
+               pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
+
        if (p->pcre2_jit_on) {
                jitret = pcre2_jit_compile(p->pcre2_pattern, 
PCRE2_JIT_COMPLETE);
-               if (jitret)
-                       die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", 
p->pattern, jitret);
+               if (jitret) {
+                       if ((opt->pcre_jit < 0) &&
+                               jitret == PCRE2_ERROR_NOMEMORY) {
+                               /*
+                                * JIT compiler isn't available but we can
+                                * still fallback to the interpreter
+                                */
+                               p->pcre2_jit_on = 0;
+                               return;
+                       }
+                       else
+                               die("Couldn't JIT the PCRE2 pattern '%s', got 
'%d'\n", p->pattern, jitret);
+               }
 
                /*
                 * The pcre2_config(PCRE2_CONFIG_JIT, ...) call just
diff --git a/grep.h b/grep.h
index c0c71eb4a9..fff152e606 100644
--- a/grep.h
+++ b/grep.h
@@ -151,6 +151,7 @@ struct grep_opt {
        int allow_textconv;
        int extended;
        int use_reflog_filter;
+       int pcre_jit;
        int pcre1;
        int pcre2;
        int relative;

base-commit: 870eea81669bfff4333b37b11fedd870cd05fd90
-- 
2.22.0

Reply via email to