Skip to content

Commit 26d2b72

Browse files
committed
Merge branch 'ab/grep-pcre2-allocfix' into next
Updates to memory allocation code around the use of pcre2 library. * ab/grep-pcre2-allocfix: grep/pcre2: move definitions of pcre2_{malloc,free} grep/pcre2: move back to thread-only PCREv2 structures grep/pcre2: actually make pcre2 use custom allocator grep/pcre2: use pcre2_maketables_free() function grep/pcre2: use compile-time PCREv2 version test grep/pcre2: add GREP_PCRE2_DEBUG_MALLOC debug mode grep/pcre2: prepare to add debugging to pcre2_malloc() grep/pcre2: correct reference to grep_init() in comment grep/pcre2: drop needless assignment to NULL grep/pcre2: drop needless assignment + assert() on opt->pcre2
2 parents b75b4e4 + c176035 commit 26d2b72

File tree

3 files changed

+51
-58
lines changed

3 files changed

+51
-58
lines changed

builtin/grep.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,5 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
11811181
run_pager(&opt, prefix);
11821182
clear_pathspec(&pathspec);
11831183
free_grep_patterns(&opt);
1184-
grep_destroy();
11851184
return !hit;
11861185
}

grep.c

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,6 @@ static struct grep_opt grep_defaults = {
4040
.output = std_output,
4141
};
4242

43-
#ifdef USE_LIBPCRE2
44-
static pcre2_general_context *pcre2_global_context;
45-
46-
static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
47-
{
48-
return malloc(size);
49-
}
50-
51-
static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
52-
{
53-
free(pointer);
54-
}
55-
#endif
56-
5743
static const char *color_grep_slots[] = {
5844
[GREP_COLOR_CONTEXT] = "context",
5945
[GREP_COLOR_FILENAME] = "filename",
@@ -152,20 +138,9 @@ int grep_config(const char *var, const char *value, void *cb)
152138
* Initialize one instance of grep_opt and copy the
153139
* default values from the template we read the configuration
154140
* information in an earlier call to git_config(grep_config).
155-
*
156-
* If using PCRE, make sure that the library is configured
157-
* to use the same allocator as Git (e.g. nedmalloc on Windows).
158-
*
159-
* Any allocated memory needs to be released in grep_destroy().
160141
*/
161142
void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)
162143
{
163-
#if defined(USE_LIBPCRE2)
164-
if (!pcre2_global_context)
165-
pcre2_global_context = pcre2_general_context_create(
166-
pcre2_malloc, pcre2_free, NULL);
167-
#endif
168-
169144
*opt = grep_defaults;
170145

171146
opt->repo = repo;
@@ -175,13 +150,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix
175150
opt->header_tail = &opt->header_list;
176151
}
177152

178-
void grep_destroy(void)
179-
{
180-
#ifdef USE_LIBPCRE2
181-
pcre2_general_context_free(pcre2_global_context);
182-
#endif
183-
}
184-
185153
static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
186154
{
187155
/*
@@ -363,6 +331,28 @@ static int is_fixed(const char *s, size_t len)
363331
}
364332

365333
#ifdef USE_LIBPCRE2
334+
#define GREP_PCRE2_DEBUG_MALLOC 0
335+
336+
static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
337+
{
338+
void *pointer = malloc(size);
339+
#if GREP_PCRE2_DEBUG_MALLOC
340+
static int count = 1;
341+
fprintf(stderr, "PCRE2:%p -> #%02d: alloc(%lu)\n", pointer, count++, size);
342+
#endif
343+
return pointer;
344+
}
345+
346+
static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
347+
{
348+
#if GREP_PCRE2_DEBUG_MALLOC
349+
static int count = 1;
350+
if (pointer)
351+
fprintf(stderr, "PCRE2:%p -> #%02d: free()\n", pointer, count++);
352+
#endif
353+
free(pointer);
354+
}
355+
366356
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
367357
{
368358
int error;
@@ -373,17 +363,20 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
373363
int patinforet;
374364
size_t jitsizearg;
375365

376-
assert(opt->pcre2);
377-
378-
p->pcre2_compile_context = NULL;
366+
/*
367+
* Call pcre2_general_context_create() before calling any
368+
* other pcre2_*(). It sets up our malloc()/free() functions
369+
* with which everything else is allocated.
370+
*/
371+
p->pcre2_general_context = pcre2_general_context_create(
372+
pcre2_malloc, pcre2_free, NULL);
373+
if (!p->pcre2_general_context)
374+
die("Couldn't allocate PCRE2 general context");
379375

380-
/* pcre2_global_context is initialized in append_grep_pattern */
381376
if (opt->ignore_case) {
382377
if (!opt->ignore_locale && has_non_ascii(p->pattern)) {
383-
if (!pcre2_global_context)
384-
BUG("pcre2_global_context uninitialized");
385-
p->pcre2_tables = pcre2_maketables(pcre2_global_context);
386-
p->pcre2_compile_context = pcre2_compile_context_create(NULL);
378+
p->pcre2_tables = pcre2_maketables(p->pcre2_general_context);
379+
p->pcre2_compile_context = pcre2_compile_context_create(p->pcre2_general_context);
387380
pcre2_set_character_tables(p->pcre2_compile_context,
388381
p->pcre2_tables);
389382
}
@@ -393,28 +386,18 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
393386
!(!opt->ignore_case && (p->fixed || p->is_fixed)))
394387
options |= (PCRE2_UTF | PCRE2_MATCH_INVALID_UTF);
395388

389+
#ifdef GIT_PCRE2_VERSION_10_36_OR_HIGHER
396390
/* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
397-
if (PCRE2_MATCH_INVALID_UTF && options & (PCRE2_UTF | PCRE2_CASELESS)) {
398-
struct strbuf buf;
399-
int len;
400-
int err;
401-
402-
if ((len = pcre2_config(PCRE2_CONFIG_VERSION, NULL)) < 0)
403-
BUG("pcre2_config(..., NULL) failed: %d", len);
404-
strbuf_init(&buf, len + 1);
405-
if ((err = pcre2_config(PCRE2_CONFIG_VERSION, buf.buf)) < 0)
406-
BUG("pcre2_config(..., buf.buf) failed: %d", err);
407-
if (versioncmp(buf.buf, "10.36") < 0)
408-
options |= PCRE2_NO_START_OPTIMIZE;
409-
strbuf_release(&buf);
410-
}
391+
if (PCRE2_MATCH_INVALID_UTF && options & (PCRE2_UTF | PCRE2_CASELESS))
392+
options |= PCRE2_NO_START_OPTIMIZE;
393+
#endif
411394

412395
p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
413396
p->patternlen, options, &error, &erroffset,
414397
p->pcre2_compile_context);
415398

416399
if (p->pcre2_pattern) {
417-
p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, NULL);
400+
p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, p->pcre2_general_context);
418401
if (!p->pcre2_match_data)
419402
die("Couldn't allocate PCRE2 match data");
420403
} else {
@@ -493,7 +476,12 @@ static void free_pcre2_pattern(struct grep_pat *p)
493476
pcre2_compile_context_free(p->pcre2_compile_context);
494477
pcre2_code_free(p->pcre2_pattern);
495478
pcre2_match_data_free(p->pcre2_match_data);
479+
#ifdef GIT_PCRE2_VERSION_10_34_OR_HIGHER
480+
pcre2_maketables_free(p->pcre2_general_context, p->pcre2_tables);
481+
#else
496482
free((void *)p->pcre2_tables);
483+
#endif
484+
pcre2_general_context_free(p->pcre2_general_context);
497485
}
498486
#else /* !USE_LIBPCRE2 */
499487
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
@@ -555,7 +543,6 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
555543
#endif
556544
if (p->fixed || p->is_fixed) {
557545
#ifdef USE_LIBPCRE2
558-
opt->pcre2 = 1;
559546
if (p->is_fixed) {
560547
compile_pcre2_pattern(p, opt);
561548
} else {

grep.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@
44
#ifdef USE_LIBPCRE2
55
#define PCRE2_CODE_UNIT_WIDTH 8
66
#include <pcre2.h>
7+
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 36) || PCRE2_MAJOR >= 11
8+
#define GIT_PCRE2_VERSION_10_36_OR_HIGHER
9+
#endif
10+
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 34) || PCRE2_MAJOR >= 11
11+
#define GIT_PCRE2_VERSION_10_34_OR_HIGHER
12+
#endif
713
#else
814
typedef int pcre2_code;
915
typedef int pcre2_match_data;
1016
typedef int pcre2_compile_context;
17+
typedef int pcre2_general_context;
1118
#endif
1219
#ifndef PCRE2_MATCH_INVALID_UTF
1320
/* PCRE2_MATCH_* dummy also with !USE_LIBPCRE2, for test-pcre2-config.c */
@@ -69,6 +76,7 @@ struct grep_pat {
6976
pcre2_code *pcre2_pattern;
7077
pcre2_match_data *pcre2_match_data;
7178
pcre2_compile_context *pcre2_compile_context;
79+
pcre2_general_context *pcre2_general_context;
7280
const uint8_t *pcre2_tables;
7381
uint32_t pcre2_jit_on;
7482
unsigned fixed:1;
@@ -161,7 +169,6 @@ struct grep_opt {
161169

162170
int grep_config(const char *var, const char *value, void *);
163171
void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);
164-
void grep_destroy(void);
165172
void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
166173

167174
void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);

0 commit comments

Comments
 (0)