Skip to content

Commit 50b6ad5

Browse files
minipli-ossgitster
authored andcommitted
grep: fall back to interpreter if JIT memory allocation fails
Under Linux systems with SELinux's 'deny_execmem' or PaX's MPROTECT enabled, the allocation of PCRE2's JIT rwx memory may be prohibited, making pcre2_jit_compile() fail with PCRE2_ERROR_NOMEMORY (-48): [user@fedora git]$ git grep -c PCRE2_JIT grep.c:1 [user@fedora git]$ # Enable SELinux's W^X policy [user@fedora git]$ sudo semanage boolean -m -1 deny_execmem [user@fedora git]$ # JIT memory allocation fails, breaking 'git grep' [user@fedora git]$ git grep -c PCRE2_JIT fatal: Couldn't JIT the PCRE2 pattern 'PCRE2_JIT', got '-48' Instead of failing hard in this case and making 'git grep' unusable on such systems, simply fall back to interpreter mode, leading to a much better user experience. As having a functional PCRE2 JIT compiler is a legitimate use case for performance reasons, we'll only do the fallback if the supposedly available JIT is found to be non-functional by attempting to JIT compile a very simple pattern. If this fails, JIT is deemed to be non-functional and we do the interpreter fallback. For all other cases, i.e. the simple pattern can be compiled but the user provided cannot, we fail hard as we do now as the reason for the failure must be the pattern itself. To aid users in helping themselves change the error message to include a hint about the '(*NO_JIT)' prefix. Also clip the pattern at 64 characters to ensure the hint will be seen by the user and not internally truncated by the die() function. Cc: Carlo Marcelo Arenas Belón <[email protected]> Signed-off-by: Mathias Krause <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c48035d commit 50b6ad5

File tree

1 file changed

+48
-2
lines changed

1 file changed

+48
-2
lines changed

grep.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,31 @@ static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
262262
free(pointer);
263263
}
264264

265+
static int pcre2_jit_functional(void)
266+
{
267+
static int jit_working = -1;
268+
pcre2_code *code;
269+
size_t off;
270+
int err;
271+
272+
if (jit_working != -1)
273+
return jit_working;
274+
275+
/*
276+
* Try to JIT compile a simple pattern to probe if the JIT is
277+
* working in general. It might fail for systems where creating
278+
* memory mappings for runtime code generation is restricted.
279+
*/
280+
code = pcre2_compile((PCRE2_SPTR)".", 1, 0, &err, &off, NULL);
281+
if (!code)
282+
return 0;
283+
284+
jit_working = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE) == 0;
285+
pcre2_code_free(code);
286+
287+
return jit_working;
288+
}
289+
265290
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
266291
{
267292
int error;
@@ -317,8 +342,29 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
317342
pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
318343
if (p->pcre2_jit_on) {
319344
jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
320-
if (jitret)
321-
die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
345+
if (jitret == PCRE2_ERROR_NOMEMORY && !pcre2_jit_functional()) {
346+
/*
347+
* Even though pcre2_config(PCRE2_CONFIG_JIT, ...)
348+
* indicated JIT support, the library might still
349+
* fail to generate JIT code for various reasons,
350+
* e.g. when SELinux's 'deny_execmem' or PaX's
351+
* MPROTECT prevent creating W|X memory mappings.
352+
*
353+
* Instead of faling hard, fall back to interpreter
354+
* mode, just as if the pattern was prefixed with
355+
* '(*NO_JIT)'.
356+
*/
357+
p->pcre2_jit_on = 0;
358+
return;
359+
} else if (jitret) {
360+
int need_clip = p->patternlen > 64;
361+
int clip_len = need_clip ? 64 : p->patternlen;
362+
die("Couldn't JIT the PCRE2 pattern '%.*s'%s, got '%d'%s",
363+
clip_len, p->pattern, need_clip ? "..." : "", jitret,
364+
pcre2_jit_functional()
365+
? "\nPerhaps prefix (*NO_JIT) to your pattern?"
366+
: "");
367+
}
322368

323369
/*
324370
* The pcre2_config(PCRE2_CONFIG_JIT, ...) call just

0 commit comments

Comments
 (0)