diff --git a/ChangeLog b/ChangeLog index 9d0bb57..2cfa580 100644 --- a/ChangeLog +++ b/ChangeLog @@ -42,6 +42,18 @@ instead of later. Previously the pre-scan carried on and could give a misleading incorrect error message. For example, /(?J)(?'a'))(?'a')/ gave a message about invalid duplicate group names. +10. It has happened that pcre2test was accidentally linked with another POSIX +regex library instead of libpcre2-posix. In this situation, a call to regcomp() +(in the other library) may succeed, returning zero, but of course putting its +own data into the regex_t block. In one example the re_pcre2_code field was +left as NULL, which made pcre2test think it had not got a compiled POSIX regex, +so it treated the next line as another pattern line, resulting in a confusing +error message. A check has been added to pcre2test to see if the data returned +from a successful call of regcomp() are valid for PCRE2's regcomp(). If they +are not, an error message is output and the pcre2test run is abandoned. The +message points out the possibility of a mis-linking. Hopefully this will avoid +some head-scratching the next time this happens. + Version 10.21 12-January-2016 ----------------------------- diff --git a/src/pcre2posix.c b/src/pcre2posix.c index ce49876..92d1b16 100644 --- a/src/pcre2posix.c +++ b/src/pcre2posix.c @@ -209,7 +209,7 @@ if ((cflags & REG_UTF) != 0) options |= PCRE2_UTF; if ((cflags & REG_UCP) != 0) options |= PCRE2_UCP; if ((cflags & REG_UNGREEDY) != 0) options |= PCRE2_UNGREEDY; -preg->cflags = cflags; +preg->re_cflags = cflags; preg->re_pcre2_code = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options, &errorcode, &erroffset, NULL); preg->re_erroffset = erroffset; @@ -275,7 +275,7 @@ if ((eflags & REG_NOTEMPTY) != 0) options |= PCRE2_NOTEMPTY; put captured strings, ensure that nmatch is zero. This will stop any attempt to write to pmatch. */ -if ((preg->cflags & REG_NOSUB) != 0 || pmatch == NULL) nmatch = 0; +if ((preg->re_cflags & REG_NOSUB) != 0 || pmatch == NULL) nmatch = 0; /* REG_STARTEND is a BSD extension, to allow for non-NUL-terminated strings. The man page from OS X says "REG_STARTEND affects only the location of the diff --git a/src/pcre2posix.h b/src/pcre2posix.h index 7b7af6c..5f2906a 100644 --- a/src/pcre2posix.h +++ b/src/pcre2posix.h @@ -98,7 +98,7 @@ typedef struct { void *re_match_data; size_t re_nsub; size_t re_erroffset; - int cflags; + int re_cflags; } regex_t; /* The structure in which a captured offset is returned. */ diff --git a/src/pcre2test.c b/src/pcre2test.c index f679327..6bf286e 100644 --- a/src/pcre2test.c +++ b/src/pcre2test.c @@ -2982,7 +2982,7 @@ for (;;) the buffer or reached the end of the file. We can detect the former by checking that the string fills the buffer, and the latter by feof(). If neither of these is true, it means we read a binary zero which has caused - strlen() to give a short length. This is a hard error because pcre2test + strlen() to give a short length. This is a hard error because pcre2test expects to work with C strings. */ if (!INTERACTIVE(f) && dlen < rlen - 1 && !feof(f)) @@ -4701,8 +4701,7 @@ if ((pat_patctl.control & CTL_POSIX) != 0) if (msg[0] == 0) fprintf(outfile, "\n"); - /* Translate PCRE2 options to POSIX options and then compile. On success, set - up a match_data block to be used for all matches. */ + /* Translate PCRE2 options to POSIX options and then compile. */ if (utf) cflags |= REG_UTF; if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0) cflags |= REG_NOSUB; @@ -4713,7 +4712,10 @@ if ((pat_patctl.control & CTL_POSIX) != 0) if ((pat_patctl.options & PCRE2_UNGREEDY) != 0) cflags |= REG_UNGREEDY; rc = regcomp(&preg, (char *)pbuffer8, cflags); - if (rc != 0) /* Failure */ + + /* Compiling failed */ + + if (rc != 0) { size_t bsize, usize; @@ -4735,6 +4737,29 @@ if ((pat_patctl.control & CTL_POSIX) != 0) } return PR_SKIP; } + + /* Compiling succeeded. Check that the values in the preg block are sensible. + It can happen that pcre2test is accidentally linked with a different POSIX + library which succeeds, but of course puts different things into preg. In + this situation, calling regfree() may cause a segfault (or invalid free() in + valgrind), so ensure that preg.re_pcre2_code is NULL, which suppresses the + calling of regfree() on exit. */ + + if (preg.re_pcre2_code == NULL || + ((pcre2_real_code_8 *)preg.re_pcre2_code)->magic_number != MAGIC_NUMBER || + ((pcre2_real_code_8 *)preg.re_pcre2_code)->top_bracket != preg.re_nsub || + preg.re_match_data == NULL || + preg.re_cflags != cflags) + { + fprintf(outfile, + "** The regcomp() function returned zero (success), but the values set\n" + "** in the preg block are not valid for PCRE2. Check that pcre2test is\n" + "** linked with PCRE2's pcre2posix module (-lpcre2-posix) and not with\n" + "** some other POSIX regex library.\n**\n"); + preg.re_pcre2_code = NULL; + return PR_ABEND; + } + return PR_OK; #endif /* SUPPORT_PCRE2_8 */ } @@ -7450,7 +7475,7 @@ if (jit_stack != NULL) #ifdef SUPPORT_PCRE2_8 #undef BITS #define BITS 8 -regfree(&preg); +if (preg.re_pcre2_code != NULL) regfree(&preg); FREECONTEXTS; #endif