diff --git a/ChangeLog b/ChangeLog index 0351ec1..f519f41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -92,6 +92,17 @@ matching to find the minimum value for this limit. memory allocation functions were used instead of whatever was used when the pattern was compiled. +17. Changes to the pcre2test "memory" modifier on a subject line. These apply +only to pcre2_match(): + + (a) Warn if null_context is set on both pattern and subject, because the + memory details cannot then be shown. + + (b) Remember (up to a certain number of) memory allocations and their + lengths, and list only the lengths, so as to be system-independent. + (In practice, the new interpreter never has more than 2 blocks allocated + simultaneously.) + Version 10.23 14-February-2017 ------------------------------ diff --git a/doc/pcre2test.1 b/doc/pcre2test.1 index 4d5dc73..ff6e53e 100644 --- a/doc/pcre2test.1 +++ b/doc/pcre2test.1 @@ -1,4 +1,4 @@ -.TH PCRE2TEST 1 "24 March 2017" "PCRE 10.30" +.TH PCRE2TEST 1 "25 March 2017" "PCRE 10.30" .SH NAME pcre2test - a program for testing Perl-compatible regular expressions. .SH SYNOPSIS @@ -1333,11 +1333,15 @@ is added to the non-match message. .SS "Showing memory usage" .rs .sp -The \fBmemory\fP modifier causes \fBpcre2test\fP to log all heap memory -allocation and freeing calls that occur during a call to \fBpcre2_match()\fP. -These occur only when a match requires a bigger vector than the default for -remembering backtracking points. In many cases there will be none. No heap -memory is allocated during matching with \fBpcre2_dfa_match\fP or with JIT. +The \fBmemory\fP modifier causes \fBpcre2test\fP to log the sizes of all heap +memory allocation and freeing calls that occur during a call to +\fBpcre2_match()\fP. These occur only when a match requires a bigger vector +than the default for remembering backtracking points. In many cases there will +be no heap memory used and therefore no additional output. No heap memory is +allocated during matching with \fBpcre2_dfa_match\fP or with JIT, so in those +cases the \fBmemory\fP modifier never has any effect. For this modifier to +work, the \fBnull_context\fP modifier must not be set on both the pattern and +the subject, though it can be set on one or the other. . . .SS "Setting a starting offset" @@ -1771,6 +1775,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 24 March 2017 +Last updated: 25 March 2017 Copyright (c) 1997-2017 University of Cambridge. .fi diff --git a/src/pcre2test.c b/src/pcre2test.c index cebd323..e758523 100644 --- a/src/pcre2test.c +++ b/src/pcre2test.c @@ -78,6 +78,10 @@ from www.cbttape.org. */ #include #endif +/* Debugging code enabler */ + +// #define DEBUG_SHOW_MALLOC_ADDRESSES + /* Both libreadline and libedit are optionally supported. The user-supplied original patch uses readline/readline.h for libedit, but in at least one system it is installed as editline/readline.h, so the configuration code now looks for @@ -188,6 +192,7 @@ void vms_setsymbol( char *, char *, int ); #define JUNK_OFFSET 0xdeadbeef /* For initializing ovector */ #define LOCALESIZE 32 /* Size of locale name */ #define LOOPREPEAT 500000 /* Default loop count for timing */ +#define MALLOCLISTSIZE 20 /* For remembering mallocs */ #define PATSTACKSIZE 20 /* Pattern stack for save/restore testing */ #define REPLACE_MODSIZE 100 /* Field for reading 8-bit replacement */ #define VERSION_SIZE 64 /* Size of buffer for the version strings */ @@ -839,6 +844,10 @@ static datctl dat_datctl; static void *patstack[PATSTACKSIZE]; static int patstacknext = 0; +static void *malloclist[MALLOCLISTSIZE]; +static PCRE2_SIZE malloclistlength[MALLOCLISTSIZE]; +static uint32_t malloclistptr = 0; + #ifdef SUPPORT_PCRE2_8 static regex_t preg = { NULL, NULL, 0, 0, 0 }; #endif @@ -2435,12 +2444,32 @@ return sys_errlist[n]; /* Alternative memory functions, to test functionality. */ -static void *my_malloc(size_t size, void *data) +static void *my_malloc(PCRE2_SIZE size, void *data) { void *block = malloc(size); (void)data; if (show_memory) - fprintf(outfile, "malloc %3d %p\n", (int)size, block); + { + if (block == NULL) + { + fprintf(outfile, "** malloc() failed for %zd\n", size); + } + else + { + fprintf(outfile, "malloc %5zd", size); +#ifdef DEBUG_SHOW_MALLOC_ADDRESSES + fprintf(outfile, " %p", block); /* Not portable */ +#endif + if (malloclistptr < MALLOCLISTSIZE) + { + malloclist[malloclistptr] = block; + malloclistlength[malloclistptr++] = size; + } + else + fprintf(outfile, " (not remembered)"); + fprintf(outfile, "\n"); + } + } return block; } @@ -2448,7 +2477,32 @@ static void my_free(void *block, void *data) { (void)data; if (show_memory) - fprintf(outfile, "free %p\n", block); + { + uint32_t i, j; + BOOL found = FALSE; + + fprintf(outfile, "free"); + for (i = 0; i < malloclistptr; i++) + { + if (block == malloclist[i]) + { + fprintf(outfile, " %5zd", malloclistlength[i]); + malloclistptr--; + for (j = i; j < malloclistptr; j++) + { + malloclist[j] = malloclist[j+1]; + malloclistlength[j] = malloclistlength[j+1]; + } + found = TRUE; + break; + } + } + if (!found) fprintf(outfile, " unremembered block"); +#ifdef DEBUG_SHOW_MALLOC_ADDRESSES + fprintf(outfile, " %p", block); /* Not portable */ +#endif + fprintf(outfile, "\n"); + } free(block); } @@ -6145,7 +6199,7 @@ if (pat_patctl.replacement[0] != 0 && fprintf(outfile, "** Replacement text is not supported with null_context.\n"); return PR_OK; } - + /* We now have the subject in dbuffer, with len containing the byte length, and ulen containing the code unit length, with a copy in arg_ulen for use in match function arguments (this gets changed to PCRE2_ZERO_TERMINATED when the @@ -6288,10 +6342,16 @@ NULL context. */ use_dat_context = ((dat_datctl.control & CTL_NULLCONTEXT) != 0)? NULL : PTR(dat_context); -/* Enable display of malloc/free if wanted. */ +/* Enable display of malloc/free if wanted. We can do this only if either the +pattern or the subject is processed with a context. */ show_memory = (dat_datctl.control & CTL_MEMORY) != 0; +if (show_memory && + (pat_patctl.control & dat_datctl.control & CTL_NULLCONTEXT) != 0) + fprintf(outfile, "** \\=memory requires either a pattern or a subject " + "context: ignored\n"); + /* Create and assign a JIT stack if requested. */ if (dat_datctl.jitstack != 0)