Merge branch 'ab/grep-pcre2-allocfix'
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->pcre2maint
commit
24119d9d7b
|
@ -1181,6 +1181,5 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||||
run_pager(&opt, prefix);
|
run_pager(&opt, prefix);
|
||||||
clear_pathspec(&pathspec);
|
clear_pathspec(&pathspec);
|
||||||
free_grep_patterns(&opt);
|
free_grep_patterns(&opt);
|
||||||
grep_destroy();
|
|
||||||
return !hit;
|
return !hit;
|
||||||
}
|
}
|
||||||
|
|
97
grep.c
97
grep.c
|
@ -40,20 +40,6 @@ static struct grep_opt grep_defaults = {
|
||||||
.output = std_output,
|
.output = std_output,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_LIBPCRE2
|
|
||||||
static pcre2_general_context *pcre2_global_context;
|
|
||||||
|
|
||||||
static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
|
|
||||||
{
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
|
|
||||||
{
|
|
||||||
free(pointer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *color_grep_slots[] = {
|
static const char *color_grep_slots[] = {
|
||||||
[GREP_COLOR_CONTEXT] = "context",
|
[GREP_COLOR_CONTEXT] = "context",
|
||||||
[GREP_COLOR_FILENAME] = "filename",
|
[GREP_COLOR_FILENAME] = "filename",
|
||||||
|
@ -152,20 +138,9 @@ int grep_config(const char *var, const char *value, void *cb)
|
||||||
* Initialize one instance of grep_opt and copy the
|
* Initialize one instance of grep_opt and copy the
|
||||||
* default values from the template we read the configuration
|
* default values from the template we read the configuration
|
||||||
* information in an earlier call to git_config(grep_config).
|
* information in an earlier call to git_config(grep_config).
|
||||||
*
|
|
||||||
* If using PCRE, make sure that the library is configured
|
|
||||||
* to use the same allocator as Git (e.g. nedmalloc on Windows).
|
|
||||||
*
|
|
||||||
* Any allocated memory needs to be released in grep_destroy().
|
|
||||||
*/
|
*/
|
||||||
void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)
|
void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)
|
||||||
{
|
{
|
||||||
#if defined(USE_LIBPCRE2)
|
|
||||||
if (!pcre2_global_context)
|
|
||||||
pcre2_global_context = pcre2_general_context_create(
|
|
||||||
pcre2_malloc, pcre2_free, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*opt = grep_defaults;
|
*opt = grep_defaults;
|
||||||
|
|
||||||
opt->repo = repo;
|
opt->repo = repo;
|
||||||
|
@ -175,13 +150,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix
|
||||||
opt->header_tail = &opt->header_list;
|
opt->header_tail = &opt->header_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void grep_destroy(void)
|
|
||||||
{
|
|
||||||
#ifdef USE_LIBPCRE2
|
|
||||||
pcre2_general_context_free(pcre2_global_context);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
|
static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -363,6 +331,28 @@ static int is_fixed(const char *s, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_LIBPCRE2
|
#ifdef USE_LIBPCRE2
|
||||||
|
#define GREP_PCRE2_DEBUG_MALLOC 0
|
||||||
|
|
||||||
|
static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
|
||||||
|
{
|
||||||
|
void *pointer = malloc(size);
|
||||||
|
#if GREP_PCRE2_DEBUG_MALLOC
|
||||||
|
static int count = 1;
|
||||||
|
fprintf(stderr, "PCRE2:%p -> #%02d: alloc(%lu)\n", pointer, count++, size);
|
||||||
|
#endif
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
|
||||||
|
{
|
||||||
|
#if GREP_PCRE2_DEBUG_MALLOC
|
||||||
|
static int count = 1;
|
||||||
|
if (pointer)
|
||||||
|
fprintf(stderr, "PCRE2:%p -> #%02d: free()\n", pointer, count++);
|
||||||
|
#endif
|
||||||
|
free(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
|
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -373,17 +363,20 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
|
||||||
int patinforet;
|
int patinforet;
|
||||||
size_t jitsizearg;
|
size_t jitsizearg;
|
||||||
|
|
||||||
assert(opt->pcre2);
|
/*
|
||||||
|
* Call pcre2_general_context_create() before calling any
|
||||||
|
* other pcre2_*(). It sets up our malloc()/free() functions
|
||||||
|
* with which everything else is allocated.
|
||||||
|
*/
|
||||||
|
p->pcre2_general_context = pcre2_general_context_create(
|
||||||
|
pcre2_malloc, pcre2_free, NULL);
|
||||||
|
if (!p->pcre2_general_context)
|
||||||
|
die("Couldn't allocate PCRE2 general context");
|
||||||
|
|
||||||
p->pcre2_compile_context = NULL;
|
|
||||||
|
|
||||||
/* pcre2_global_context is initialized in append_grep_pattern */
|
|
||||||
if (opt->ignore_case) {
|
if (opt->ignore_case) {
|
||||||
if (!opt->ignore_locale && has_non_ascii(p->pattern)) {
|
if (!opt->ignore_locale && has_non_ascii(p->pattern)) {
|
||||||
if (!pcre2_global_context)
|
p->pcre2_tables = pcre2_maketables(p->pcre2_general_context);
|
||||||
BUG("pcre2_global_context uninitialized");
|
p->pcre2_compile_context = pcre2_compile_context_create(p->pcre2_general_context);
|
||||||
p->pcre2_tables = pcre2_maketables(pcre2_global_context);
|
|
||||||
p->pcre2_compile_context = pcre2_compile_context_create(NULL);
|
|
||||||
pcre2_set_character_tables(p->pcre2_compile_context,
|
pcre2_set_character_tables(p->pcre2_compile_context,
|
||||||
p->pcre2_tables);
|
p->pcre2_tables);
|
||||||
}
|
}
|
||||||
|
@ -393,28 +386,18 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
|
||||||
!(!opt->ignore_case && (p->fixed || p->is_fixed)))
|
!(!opt->ignore_case && (p->fixed || p->is_fixed)))
|
||||||
options |= (PCRE2_UTF | PCRE2_MATCH_INVALID_UTF);
|
options |= (PCRE2_UTF | PCRE2_MATCH_INVALID_UTF);
|
||||||
|
|
||||||
|
#ifdef GIT_PCRE2_VERSION_10_36_OR_HIGHER
|
||||||
/* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
|
/* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
|
||||||
if (PCRE2_MATCH_INVALID_UTF && options & (PCRE2_UTF | PCRE2_CASELESS)) {
|
if (PCRE2_MATCH_INVALID_UTF && options & (PCRE2_UTF | PCRE2_CASELESS))
|
||||||
struct strbuf buf;
|
|
||||||
int len;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if ((len = pcre2_config(PCRE2_CONFIG_VERSION, NULL)) < 0)
|
|
||||||
BUG("pcre2_config(..., NULL) failed: %d", len);
|
|
||||||
strbuf_init(&buf, len + 1);
|
|
||||||
if ((err = pcre2_config(PCRE2_CONFIG_VERSION, buf.buf)) < 0)
|
|
||||||
BUG("pcre2_config(..., buf.buf) failed: %d", err);
|
|
||||||
if (versioncmp(buf.buf, "10.36") < 0)
|
|
||||||
options |= PCRE2_NO_START_OPTIMIZE;
|
options |= PCRE2_NO_START_OPTIMIZE;
|
||||||
strbuf_release(&buf);
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
|
p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
|
||||||
p->patternlen, options, &error, &erroffset,
|
p->patternlen, options, &error, &erroffset,
|
||||||
p->pcre2_compile_context);
|
p->pcre2_compile_context);
|
||||||
|
|
||||||
if (p->pcre2_pattern) {
|
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, p->pcre2_general_context);
|
||||||
if (!p->pcre2_match_data)
|
if (!p->pcre2_match_data)
|
||||||
die("Couldn't allocate PCRE2 match data");
|
die("Couldn't allocate PCRE2 match data");
|
||||||
} else {
|
} else {
|
||||||
|
@ -493,7 +476,12 @@ static void free_pcre2_pattern(struct grep_pat *p)
|
||||||
pcre2_compile_context_free(p->pcre2_compile_context);
|
pcre2_compile_context_free(p->pcre2_compile_context);
|
||||||
pcre2_code_free(p->pcre2_pattern);
|
pcre2_code_free(p->pcre2_pattern);
|
||||||
pcre2_match_data_free(p->pcre2_match_data);
|
pcre2_match_data_free(p->pcre2_match_data);
|
||||||
|
#ifdef GIT_PCRE2_VERSION_10_34_OR_HIGHER
|
||||||
|
pcre2_maketables_free(p->pcre2_general_context, p->pcre2_tables);
|
||||||
|
#else
|
||||||
free((void *)p->pcre2_tables);
|
free((void *)p->pcre2_tables);
|
||||||
|
#endif
|
||||||
|
pcre2_general_context_free(p->pcre2_general_context);
|
||||||
}
|
}
|
||||||
#else /* !USE_LIBPCRE2 */
|
#else /* !USE_LIBPCRE2 */
|
||||||
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
|
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)
|
||||||
#endif
|
#endif
|
||||||
if (p->fixed || p->is_fixed) {
|
if (p->fixed || p->is_fixed) {
|
||||||
#ifdef USE_LIBPCRE2
|
#ifdef USE_LIBPCRE2
|
||||||
opt->pcre2 = 1;
|
|
||||||
if (p->is_fixed) {
|
if (p->is_fixed) {
|
||||||
compile_pcre2_pattern(p, opt);
|
compile_pcre2_pattern(p, opt);
|
||||||
} else {
|
} else {
|
||||||
|
|
9
grep.h
9
grep.h
|
@ -4,10 +4,17 @@
|
||||||
#ifdef USE_LIBPCRE2
|
#ifdef USE_LIBPCRE2
|
||||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
#include <pcre2.h>
|
#include <pcre2.h>
|
||||||
|
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 36) || PCRE2_MAJOR >= 11
|
||||||
|
#define GIT_PCRE2_VERSION_10_36_OR_HIGHER
|
||||||
|
#endif
|
||||||
|
#if (PCRE2_MAJOR >= 10 && PCRE2_MINOR >= 34) || PCRE2_MAJOR >= 11
|
||||||
|
#define GIT_PCRE2_VERSION_10_34_OR_HIGHER
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
typedef int pcre2_code;
|
typedef int pcre2_code;
|
||||||
typedef int pcre2_match_data;
|
typedef int pcre2_match_data;
|
||||||
typedef int pcre2_compile_context;
|
typedef int pcre2_compile_context;
|
||||||
|
typedef int pcre2_general_context;
|
||||||
#endif
|
#endif
|
||||||
#ifndef PCRE2_MATCH_INVALID_UTF
|
#ifndef PCRE2_MATCH_INVALID_UTF
|
||||||
/* PCRE2_MATCH_* dummy also with !USE_LIBPCRE2, for test-pcre2-config.c */
|
/* PCRE2_MATCH_* dummy also with !USE_LIBPCRE2, for test-pcre2-config.c */
|
||||||
|
@ -69,6 +76,7 @@ struct grep_pat {
|
||||||
pcre2_code *pcre2_pattern;
|
pcre2_code *pcre2_pattern;
|
||||||
pcre2_match_data *pcre2_match_data;
|
pcre2_match_data *pcre2_match_data;
|
||||||
pcre2_compile_context *pcre2_compile_context;
|
pcre2_compile_context *pcre2_compile_context;
|
||||||
|
pcre2_general_context *pcre2_general_context;
|
||||||
const uint8_t *pcre2_tables;
|
const uint8_t *pcre2_tables;
|
||||||
uint32_t pcre2_jit_on;
|
uint32_t pcre2_jit_on;
|
||||||
unsigned fixed:1;
|
unsigned fixed:1;
|
||||||
|
@ -161,7 +169,6 @@ struct grep_opt {
|
||||||
|
|
||||||
int grep_config(const char *var, const char *value, void *);
|
int grep_config(const char *var, const char *value, void *);
|
||||||
void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);
|
void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);
|
||||||
void grep_destroy(void);
|
|
||||||
void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
|
void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
|
||||||
|
|
||||||
void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
|
void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
|
||||||
|
|
Loading…
Reference in New Issue