From: Johannes Schindelin <johannes.schindelin@xxxxxx> Since 7d3bf769994 (grep: avoid leak of chartables in PCRE2, 2019-08-01), we try to release the UTF-8 tables obtained via `pcre2_maketables()`. To do that, we use the function `free()`. That is all fine and dandy as long as that refers to the system allocator. However, when we compile Git with `USE_NED_ALLOCATOR` (notably on Windows), then `free()` actually calls `nedfree()`. But `pcre2_maketables()` allocated the tables using the system allocator because we did not tell it to use nedmalloc instead. This leads to segmentation faults when the UTF-8 tables are released, most notably in the `t7816-grep-binary-pattern.sh` test script. PCRE2 does have an option to override the allocator it should use, and this patch calls upon it. As there are other ways to override the system allocator than `USE_NED_ALLOCATOR`, we choose to specify the allocator we want to use specifically, even if we still use the system allocator. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- grep.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/grep.c b/grep.c index d4c5d464ad..d6d29fc724 100644 --- a/grep.c +++ b/grep.c @@ -482,6 +482,27 @@ static void free_pcre1_regexp(struct grep_pat *p) #endif /* !USE_LIBPCRE1 */ #ifdef USE_LIBPCRE2 +static void *pcre2_malloc(PCRE2_SIZE size, void *memory_data) +{ + return malloc(size); +} + +static void pcre2_free(void *pointer, void *memory_data) +{ + return free(pointer); +} + +static pcre2_general_context *get_pcre2_context(void) +{ + static pcre2_general_context *context; + + if (!context) + context = pcre2_general_context_create(pcre2_malloc, + pcre2_free, NULL); + + return context; +} + static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt) { int error; @@ -498,8 +519,9 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt if (opt->ignore_case) { if (has_non_ascii(p->pattern)) { - p->pcre2_tables = pcre2_maketables(NULL); - p->pcre2_compile_context = pcre2_compile_context_create(NULL); + p->pcre2_tables = pcre2_maketables(get_pcre2_context()); + p->pcre2_compile_context = + pcre2_compile_context_create(get_pcre2_context()); pcre2_set_character_tables(p->pcre2_compile_context, p->pcre2_tables); } @@ -513,7 +535,8 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt p->pcre2_compile_context); if (p->pcre2_pattern) { - p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, NULL); + p->pcre2_match_data = + pcre2_match_data_create_from_pattern(p->pcre2_pattern, get_pcre2_context()); if (!p->pcre2_match_data) die("Couldn't allocate PCRE2 match data"); } else { @@ -550,7 +573,7 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt return; } - p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL); + p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, get_pcre2_context()); if (!p->pcre2_jit_stack) die("Couldn't allocate PCRE2 JIT stack"); p->pcre2_match_context = pcre2_match_context_create(NULL); -- gitgitgadget