X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=pcrs.c;h=007f7cc104d9b9cb40648434f938a597df30508c;hp=c513251a2ed2c709e2486c624374759e8a28ce2b;hb=HEAD;hpb=0b3c51a627189ae9f63bdcd35fee5889feda50cc diff --git a/pcrs.c b/pcrs.c index c513251a..eaeea625 100644 --- a/pcrs.c +++ b/pcrs.c @@ -1,4 +1,3 @@ -const char pcrs_rcs[] = "$Id: pcrs.c,v 1.32 2009/05/19 17:44:22 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/pcrs.c,v $ @@ -16,22 +15,21 @@ const char pcrs_rcs[] = "$Id: pcrs.c,v 1.32 2009/05/19 17:44:22 fabiankeil Exp $ * * Copyright (C) 2006, 2007 Fabian Keil * - * This program is free software; you can redistribute it - * and/or modify it under the terms of the GNU Lesser - * General Public License (LGPL), version 2.1, which should - * be included in this distribution (see LICENSE.txt), with - * the exception that the permission to replace that license - * with the GNU General Public License (GPL) given in section - * 3 is restricted to version 2 of the GPL. + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at + * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the license for more details. + * PARTICULAR PURPOSE. See the GNU General Public + * License for more details. * - * The GNU Lesser General Public License should be included - * with this file. If not, you can view it at - * http://www.gnu.org/licenses/lgpl.html + * The GNU General Public License should be included with + * this file. If not, you can view it at + * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * @@ -55,13 +53,11 @@ const char pcrs_rcs[] = "$Id: pcrs.c,v 1.32 2009/05/19 17:44:22 fabiankeil Exp $ #include "pcrs.h" -const char pcrs_h_rcs[] = PCRS_H_VERSION; - /* * Internal prototypes */ -static int pcrs_parse_perl_options(const char *optstring, int *flags); +static int pcrs_parse_perl_options(const char *optstring, unsigned int *flags); static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int trivialflag, int capturecount, int *errptr); static int is_hex_sequence(const char *sequence); @@ -71,7 +67,7 @@ static int is_hex_sequence(const char *sequence); * Function : pcrs_strerror * * Description : Return a string describing a given error code. - * + * * Parameters : * 1 : error = the error code * @@ -80,30 +76,32 @@ static int is_hex_sequence(const char *sequence); *********************************************************************/ const char *pcrs_strerror(const int error) { - if (error < 0) + static char buf[100]; + + if (error != 0) { switch (error) { /* Passed-through PCRE error: */ - case PCRE_ERROR_NOMEMORY: return "(pcre:) No memory"; + case PCREn(ERROR_NOMEMORY): return "(pcre:) No memory"; /* Shouldn't happen unless PCRE or PCRS bug, or user messed with compiled job: */ - case PCRE_ERROR_NULL: return "(pcre:) NULL code or subject or ovector"; - case PCRE_ERROR_BADOPTION: return "(pcre:) Unrecognized option bit"; - case PCRE_ERROR_BADMAGIC: return "(pcre:) Bad magic number in code"; + case PCREn(ERROR_NULL): return "(pcre:) NULL code or subject or ovector"; + case PCREn(ERROR_BADOPTION): return "(pcre:) Unrecognized option bit"; + case PCREn(ERROR_BADMAGIC): return "(pcre:) Bad magic number in code"; +#if defined(PCRE_ERROR_UNKNOWN_NODE) case PCRE_ERROR_UNKNOWN_NODE: return "(pcre:) Bad node in pattern"; - +#endif /* Can't happen / not passed: */ - case PCRE_ERROR_NOSUBSTRING: return "(pcre:) Fire in power supply"; - case PCRE_ERROR_NOMATCH: return "(pcre:) Water in power supply"; + case PCREn(ERROR_NOSUBSTRING): return "(pcre:) Fire in power supply"; + case PCREn(ERROR_NOMATCH): return "(pcre:) Water in power supply"; #ifdef PCRE_ERROR_MATCHLIMIT /* * Only reported by PCRE versions newer than our own. */ - case PCRE_ERROR_MATCHLIMIT: return "(pcre:) Match limit reached"; + case PCREn(ERROR_MATCHLIMIT): return "(pcre:) Match limit reached"; #endif /* def PCRE_ERROR_MATCHLIMIT */ - /* PCRS errors: */ case PCRS_ERR_NOMEM: return "(pcrs:) No memory"; case PCRS_ERR_CMDSYNTAX: return "(pcrs:) Syntax error while parsing command"; @@ -113,13 +111,15 @@ const char *pcrs_strerror(const int error) case PCRS_WARN_TRUNCATION: return "(pcrs:) At least one variable was too big and has been truncated before compilation"; - /* - * XXX: With the exception of PCRE_ERROR_MATCHLIMIT we - * only catch PCRE errors that can happen with our internal - * version. If Privoxy is linked against a newer - * PCRE version all bets are off ... - */ - default: return "Unknown error. Privoxy out of sync with PCRE?"; + default: +#ifdef HAVE_PCRE2 + pcre2_get_error_message(error, (PCRE2_UCHAR8*)buf, sizeof(buf)); +#else + snprintf(buf, sizeof(buf), + "Error code %d. For details, check the pcre documentation.", + error); +#endif + return buf; } } /* error >= 0: No error */ @@ -139,15 +139,15 @@ const char *pcrs_strerror(const int error) * 'T' (trivial) options but pcrs needs them, the corresponding * flags are set if 'g'or 'T' is encountered. * Note: The 'T' and 'U' options do not conform to Perl. - * + * * Parameters : * 1 : optstring = string with options in perl syntax * 2 : flags = see description * - * Returns : option integer suitable for pcre + * Returns : option integer suitable for pcre * *********************************************************************/ -static int pcrs_parse_perl_options(const char *optstring, int *flags) +static int pcrs_parse_perl_options(const char *optstring, unsigned int *flags) { size_t i; int rc = 0; @@ -161,12 +161,13 @@ static int pcrs_parse_perl_options(const char *optstring, int *flags) { case 'e': break; /* ToDo ;-) */ case 'g': *flags |= PCRS_GLOBAL; break; - case 'i': rc |= PCRE_CASELESS; break; - case 'm': rc |= PCRE_MULTILINE; break; + case 'i': rc |= PCREn(CASELESS); break; + case 'm': rc |= PCREn(MULTILINE); break; case 'o': break; - case 's': rc |= PCRE_DOTALL; break; - case 'x': rc |= PCRE_EXTENDED; break; - case 'U': rc |= PCRE_UNGREEDY; break; + case 's': rc |= PCREn(DOTALL); break; + case 'x': rc |= PCREn(EXTENDED); break; + case 'D': *flags |= PCRS_DYNAMIC; break; + case 'U': rc |= PCREn(UNGREEDY); break; case 'T': *flags |= PCRS_TRIVIAL; break; default: break; } @@ -176,6 +177,38 @@ static int pcrs_parse_perl_options(const char *optstring, int *flags) } +#ifdef FUZZ +/********************************************************************* + * + * Function : pcrs_compile_fuzzed_replacement + * + * Description : Wrapper around pcrs_compile_replacement() for + * fuzzing purposes. + * + * Parameters : + * 1 : replacement = replacement part of s/// operator + * in perl syntax + * 2 : errptr = pointer to an integer in which error + * conditions can be returned. + * + * Returns : pcrs_substitute data structure, or NULL if an + * error is encountered. In that case, *errptr has + * the reason. + * + *********************************************************************/ +extern pcrs_substitute *pcrs_compile_fuzzed_replacement(const char *replacement, int *errptr) +{ + int capturecount = PCRS_MAX_SUBMATCHES; /* XXX: fuzzworthy? */ + int trivial_flag = 0; /* We don't want to fuzz strncpy() */ + + *errptr = 0; /* XXX: Should pcrs_compile_replacement() do this? */ + + return pcrs_compile_replacement(replacement, trivial_flag, capturecount, errptr); + +} +#endif + + /********************************************************************* * * Function : pcrs_compile_replacement @@ -203,10 +236,13 @@ static int pcrs_parse_perl_options(const char *optstring, int *flags) static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int trivialflag, int capturecount, int *errptr) { int i, k, l, quoted; - size_t length; char *text; pcrs_substitute *r; - +#ifndef FUZZ + size_t length; +#else + static size_t length; +#endif i = k = l = quoted = 0; /* @@ -236,14 +272,14 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr return NULL; } memset(text, '\0', length + 1); - + /* * In trivial mode, just copy the substitute text */ if (trivialflag) { - text = strncpy(text, replacement, length + 1); + strlcpy(text, replacement, length + 1); k = (int)length; } @@ -301,11 +337,11 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr */ const int ascii_value = xtoi(&replacement[i+2]); - assert(ascii_value > 0); + assert(ascii_value >= 0); assert(ascii_value < 256); text[k++] = (char)ascii_value; i += 4; - } + } else { quoted = 1; @@ -319,6 +355,13 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr if (replacement[i] == '$' && !quoted && i < (int)(length - 1)) { char *symbol, symbols[] = "'`+&"; + if (l >= PCRS_MAX_SUBMATCHES) + { + freez(text); + freez(r); + *errptr = PCRS_WARN_BADREF; + return NULL; + } r->block_length[l] = (size_t)(k - r->block_offset[l]); /* Numerical backreferences */ @@ -330,14 +373,17 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr } if (r->backref[l] > capturecount) { + freez(text); + freez(r); *errptr = PCRS_WARN_BADREF; + return NULL; } } /* Symbolic backreferences: */ else if (NULL != (symbol = strchr(symbols, replacement[i + 1]))) { - + if (symbol - symbols == 2) /* $+ */ { r->backref[l] = capturecount; @@ -348,7 +394,7 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr } else /* $' or $` */ { - r->backref[l] = PCRS_MAX_SUBMATCHES + 1 - (symbol - symbols); + r->backref[l] = (int)(PCRS_MAX_SUBMATCHES + 1 - (symbol - symbols)); } i += 2; } @@ -359,19 +405,25 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr goto plainchar; } + assert(r->backref[l] < PCRS_MAX_SUBMATCHES + 2); /* Valid and in range? -> record */ - if (r->backref[l] < PCRS_MAX_SUBMATCHES + 2) + if ((0 <= r->backref[l]) && + (r->backref[l] < PCRS_MAX_SUBMATCHES + 2) && + (l < PCRS_MAX_SUBMATCHES - 1)) { r->backref_count[r->backref[l]] += 1; r->block_offset[++l] = k; } else { + freez(text); + freez(r); *errptr = PCRS_WARN_BADREF; - } + return NULL; + } continue; } - + plainchar: /* Plain chars are copied */ text[k++] = replacement[i++]; @@ -397,13 +449,13 @@ plainchar: * Function : pcrs_free_job * * Description : Frees the memory used by a pcrs_job struct and its - * dependant structures. + * dependent structures. * * Parameters : * 1 : job = pointer to the pcrs_job structure to be freed * * Returns : a pointer to the next job, if there was any, or - * NULL otherwise. + * NULL otherwise. * *********************************************************************/ pcrs_job *pcrs_free_job(pcrs_job *job) @@ -417,8 +469,24 @@ pcrs_job *pcrs_free_job(pcrs_job *job) else { next = job->next; - if (job->pattern != NULL) free(job->pattern); - if (job->hints != NULL) free(job->hints); + if (job->pattern != NULL) + { +#ifdef HAVE_PCRE2 + pcre2_code_free(job->pattern); +#else + free(job->pattern); +#endif + } +#ifndef HAVE_PCRE2 + if (job->hints != NULL) + { +#ifdef PCRE_CONFIG_JIT + pcre_free_study(job->hints); +#else + free(job->hints); +#endif + } +#endif if (job->substitute != NULL) { if (job->substitute->text != NULL) free(job->substitute->text); @@ -447,7 +515,7 @@ pcrs_job *pcrs_free_job(pcrs_job *job) *********************************************************************/ void pcrs_free_joblist(pcrs_job *joblist) { - while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}; + while (NULL != (joblist = pcrs_free_job(joblist))) {}; return; @@ -458,7 +526,7 @@ void pcrs_free_joblist(pcrs_job *joblist) * * Function : pcrs_compile_command * - * Description : Parses a string with a Perl-style s/// command, + * Description : Parses a string with a Perl-style s/// command, * calls pcrs_compile, and returns a corresponding * pcrs_job, or NULL if parsing or compiling the job * fails. @@ -478,11 +546,11 @@ pcrs_job *pcrs_compile_command(const char *command, int *errptr) int i, k, l, quoted = FALSE; size_t limit; char delimiter; - char *tokens[4]; + char *tokens[4]; pcrs_job *newjob; - + k = l = 0; - + /* * Tokenize the perl command */ @@ -501,7 +569,7 @@ pcrs_job *pcrs_compile_command(const char *command, int *errptr) for (i = 0; i <= (int)limit; i++) { - + if (command[i] == delimiter && !quoted) { if (l == 3) @@ -513,7 +581,7 @@ pcrs_job *pcrs_compile_command(const char *command, int *errptr) tokens[++l] = tokens[0] + k; continue; } - + else if (command[i] == '\\' && !quoted) { quoted = TRUE; @@ -535,11 +603,11 @@ pcrs_job *pcrs_compile_command(const char *command, int *errptr) free(tokens[0]); return NULL; } - + newjob = pcrs_compile(tokens[1], tokens[2], tokens[3], errptr); free(tokens[0]); return newjob; - + } @@ -565,20 +633,25 @@ pcrs_job *pcrs_compile_command(const char *command, int *errptr) pcrs_job *pcrs_compile(const char *pattern, const char *substitute, const char *options, int *errptr) { pcrs_job *newjob; - int flags; + unsigned int flags; int capturecount; +#ifdef HAVE_PCRE2 + int ret; +#else + int pcre_study_options = 0; const char *error; +#endif *errptr = 0; - /* + /* * Handle NULL arguments */ if (pattern == NULL) pattern = ""; if (substitute == NULL) substitute = ""; - /* + /* * Get and init memory */ if (NULL == (newjob = (pcrs_job *)malloc(sizeof(pcrs_job)))) @@ -599,37 +672,70 @@ pcrs_job *pcrs_compile(const char *pattern, const char *substitute, const char * /* * Compile the pattern */ +#ifdef HAVE_PCRE2 + PCRE2_SIZE error_offset; + newjob->pattern = pcre2_compile((const unsigned char *)pattern, + PCRE2_ZERO_TERMINATED, (unsigned)newjob->options, errptr, + &error_offset, NULL); +#else newjob->pattern = pcre_compile(pattern, newjob->options, &error, errptr, NULL); +#endif if (newjob->pattern == NULL) { pcrs_free_job(newjob); return NULL; } +#if defined(PCRE_STUDY_JIT_COMPILE) || defined(HAVE_PCRE2) +#ifdef DISABLE_PCRE_JIT_COMPILATION +#warning PCRE_STUDY_JIT_COMPILE is supported but Privoxy has been configured not to use it +#else + if (!(flags & PCRS_DYNAMIC)) + { +#ifdef HAVE_PCRE2 + /* Try to enable JIT compilation but continue if it's unsupported. */ + if ((ret = pcre2_jit_compile(newjob->pattern, PCRE2_JIT_COMPLETE)) && + (ret != PCRE2_ERROR_JIT_BADOPTION)) + { + *errptr = ret; + pcrs_free_job(newjob); + return NULL; + } +#else + pcre_study_options = PCRE_STUDY_JIT_COMPILE; +#endif + } +#endif +#endif +#ifndef HAVE_PCRE2 /* * Generate hints. This has little overhead, since the * hints will be NULL for a boring pattern anyway. */ - newjob->hints = pcre_study(newjob->pattern, 0, &error); + newjob->hints = pcre_study(newjob->pattern, pcre_study_options, &error); if (error != NULL) { *errptr = PCRS_ERR_STUDY; pcrs_free_job(newjob); return NULL; } - +#endif - /* - * Determine the number of capturing subpatterns. + /* + * Determine the number of capturing subpatterns. * This is needed for handling $+ in the substitute. */ +#ifdef HAVE_PCRE2 + if (0 > (*errptr = pcre2_pattern_info(newjob->pattern, PCRE2_INFO_CAPTURECOUNT, &capturecount))) +#else if (0 > (*errptr = pcre_fullinfo(newjob->pattern, newjob->hints, PCRE_INFO_CAPTURECOUNT, &capturecount))) +#endif { pcrs_free_job(newjob); return NULL; } - + /* * Compile the substitute @@ -639,7 +745,7 @@ pcrs_job *pcrs_compile(const char *pattern, const char *substitute, const char * pcrs_free_job(newjob); return NULL; } - + return newjob; } @@ -654,7 +760,7 @@ pcrs_job *pcrs_compile(const char *pattern, const char *substitute, const char * * the joblist to the subject. * The subject itself is left untouched, memory for the result * is malloc()ed and it is the caller's responsibility to free - * the result when it's no longer needed. + * the result when it's no longer needed. * * Note: For convenient string handling, a null byte is * appended to the result. It does not count towards the @@ -664,8 +770,8 @@ pcrs_job *pcrs_compile(const char *pattern, const char *substitute, const char * * Parameters : * 1 : joblist = the chained list of pcrs_jobs to be executed * 2 : subject = the subject string - * 3 : subject_length = the subject's length - * 4 : result = char** for returning the result + * 3 : subject_length = the subject's length + * 4 : result = char** for returning the result * 5 : result_length = size_t* for returning the result's length * * Returns : On success, the number of substitutions that were made. @@ -679,7 +785,7 @@ int pcrs_execute_list(pcrs_job *joblist, char *subject, size_t subject_length, c pcrs_job *job; char *old, *new = NULL; int hits, total_hits; - + old = subject; *result_length = subject_length; total_hits = 0; @@ -724,8 +830,8 @@ int pcrs_execute_list(pcrs_job *joblist, char *subject, size_t subject_length, c * Parameters : * 1 : job = the pcrs_job to be executed * 2 : subject = the subject (== original) string - * 3 : subject_length = the subject's length - * 4 : result = char** for returning the result + * 3 : subject_length = the subject's length + * 4 : result = char** for returning the result (NULL on error) * 5 : result_length = size_t* for returning the result's length * * Returns : On success, the number of substitutions that were made. @@ -736,58 +842,74 @@ int pcrs_execute_list(pcrs_job *joblist, char *subject, size_t subject_length, c *********************************************************************/ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char **result, size_t *result_length) { - int offsets[3 * PCRS_MAX_SUBMATCHES], - offset, + int offset, i, k, matches_found, submatches, max_matches = PCRS_MAX_MATCH_INIT; size_t newsize; +#ifdef HAVE_PCRE2 + pcrs_match *matches, *dummy; + pcre2_match_data *pcre2_matches; + size_t *offsets; +#else pcrs_match *matches, *dummy; + int offsets[3 * PCRS_MAX_SUBMATCHES]; +#endif char *result_offset; offset = i = 0; + *result = NULL; - /* + /* * Sanity check & memory allocation */ if (job == NULL || job->pattern == NULL || job->substitute == NULL || NULL == subject) { - *result = NULL; return(PCRS_ERR_BADJOB); } +#ifdef HAVE_PCRE2 + if (NULL == (pcre2_matches = pcre2_match_data_create_from_pattern(job->pattern, NULL))) + { + return(PCRS_ERR_NOMEM); + } + offsets = pcre2_get_ovector_pointer(pcre2_matches); +#endif if (NULL == (matches = (pcrs_match *)malloc((size_t)max_matches * sizeof(pcrs_match)))) { - *result = NULL; return(PCRS_ERR_NOMEM); } memset(matches, '\0', (size_t)max_matches * sizeof(pcrs_match)); - /* * Find the pattern and calculate the space * requirements for the result */ newsize = subject_length; +#ifdef HAVE_PCRE2 + while ((submatches = pcre2_match(job->pattern, (const unsigned char *)subject, + subject_length, (size_t)offset, 0, pcre2_matches, NULL)) > 0) +#else while ((submatches = pcre_exec(job->pattern, job->hints, subject, (int)subject_length, offset, 0, offsets, 3 * PCRS_MAX_SUBMATCHES)) > 0) +#endif { job->flags |= PCRS_SUCCESS; matches[i].submatches = submatches; for (k = 0; k < submatches; k++) { - matches[i].submatch_offset[k] = offsets[2 * k]; + matches[i].submatch_offset[k] = (int)offsets[2 * k]; /* Note: Non-found optional submatches have length -1-(-1)==0 */ - matches[i].submatch_length[k] = (size_t)(offsets[2 * k + 1] - offsets[2 * k]); + matches[i].submatch_length[k] = (size_t)(offsets[2 * k + 1] - offsets[2 * k]); /* reserve mem for each submatch as often as it is ref'd */ newsize += matches[i].submatch_length[k] * (size_t)job->substitute->backref_count[k]; } /* plus replacement text size minus match text size */ - newsize += job->substitute->length - matches[i].submatch_length[0]; + newsize += job->substitute->length - matches[i].submatch_length[0]; /* chunk before match */ matches[i].submatch_offset[PCRS_MAX_SUBMATCHES] = 0; @@ -795,7 +917,7 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char newsize += (size_t)offsets[0] * (size_t)job->substitute->backref_count[PCRS_MAX_SUBMATCHES]; /* chunk after match */ - matches[i].submatch_offset[PCRS_MAX_SUBMATCHES + 1] = offsets[1]; + matches[i].submatch_offset[PCRS_MAX_SUBMATCHES + 1] = (int)offsets[1]; matches[i].submatch_length[PCRS_MAX_SUBMATCHES + 1] = subject_length - (size_t)offsets[1] - 1; newsize += (subject_length - (size_t)offsets[1]) * (size_t)job->substitute->backref_count[PCRS_MAX_SUBMATCHES + 1]; @@ -806,7 +928,6 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char if (NULL == (dummy = (pcrs_match *)realloc(matches, (size_t)max_matches * sizeof(pcrs_match)))) { free(matches); - *result = NULL; return(PCRS_ERR_NOMEM); } matches = dummy; @@ -823,24 +944,41 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char break; /* Go find the next one */ else - offset = offsets[1]; + offset = (int)offsets[1]; } - /* Pass pcre error through if (bad) failiure */ + /* Pass pcre error through if (bad) failure */ +#ifdef HAVE_PCRE2 + if (submatches < PCRE2_ERROR_NOMATCH) +#else if (submatches < PCRE_ERROR_NOMATCH) +#endif { free(matches); - return submatches; +#ifdef HAVE_PCRE2 + pcre2_match_data_free(pcre2_matches); +#endif + return submatches; } matches_found = i; - /* + /* * Get memory for the result (must be freed by caller!) * and append terminating null byte. */ - if ((*result = (char *)malloc(newsize + 1)) == NULL) + if ((*result = (char *)malloc(newsize + 1 +#ifdef HAVE_PCRE2 + /* + * Work around to prevent invalid reads in the jit code. + */ + + 16 +#endif + )) == NULL) { free(matches); +#ifdef HAVE_PCRE2 + pcre2_match_data_free(pcre2_matches); +#endif return PCRS_ERR_NOMEM; } else @@ -849,7 +987,7 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char } - /* + /* * Replace */ offset = 0; @@ -858,7 +996,7 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char for (i = 0; i < matches_found; i++) { /* copy the chunk preceding the match */ - memcpy(result_offset, subject + offset, (size_t)(matches[i].submatch_offset[0] - offset)); + memcpy(result_offset, subject + offset, (size_t)(matches[i].submatch_offset[0] - offset)); result_offset += matches[i].submatch_offset[0] - offset; /* For every segment of the substitute.. */ @@ -893,6 +1031,9 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char memcpy(result_offset, subject + offset, subject_length - (size_t)offset); *result_length = newsize; +#ifdef HAVE_PCRE2 + pcre2_match_data_free(pcre2_matches); +#endif free(matches); return matches_found; @@ -944,7 +1085,7 @@ static int is_hex_sequence(const char *sequence) * FALSE * *********************************************************************/ -int pcrs_job_is_dynamic (char *job) +int pcrs_job_is_dynamic(char *job) { const char delimiter = job[1]; const size_t length = strlen(job); @@ -988,7 +1129,7 @@ int pcrs_job_is_dynamic (char *job) * Parameters : * 1 : string = The string to search in * - * Returns : A safe delimiter if one was found, otherwise '\0'. + * Returns : A safe delimiter if one was found, otherwise '\0'. * *********************************************************************/ char pcrs_get_delimiter(const char *string) @@ -997,8 +1138,8 @@ char pcrs_get_delimiter(const char *string) * Some characters that are unlikely to * be part of pcrs replacement strings. */ - char delimiters[] = "><§#+*~%^°-:;µ!@"; - char *d = delimiters; + static const char delimiters[] = "><#+*~%^-:;!@"; + const char *d = delimiters; /* Take the first delimiter that isn't part of the string */ while (*d && NULL != strchr(string, *d)) @@ -1021,16 +1162,16 @@ char pcrs_get_delimiter(const char *string) * * Parameters : * 1 : subject = the subject (== original) string - * 2 : pcrs_command = the pcrs command as string (s@foo@bar@) - * 3 : hits = int* for returning the number of modifications + * 2 : pcrs_command = the pcrs command as string (s@foo@bar@) + * 3 : hits = int* for returning the number of modifications * * Returns : NULL in case of errors, otherwise the - * result of the pcrs command. + * result of the pcrs command. * *********************************************************************/ char *pcrs_execute_single_command(const char *subject, const char *pcrs_command, int *hits) { - size_t size; + size_t buffer_size, new_size; char *result = NULL; pcrs_job *job; @@ -1038,12 +1179,12 @@ char *pcrs_execute_single_command(const char *subject, const char *pcrs_command, assert(pcrs_command); *hits = 0; - size = strlen(subject); + buffer_size = strlen(subject); job = pcrs_compile_command(pcrs_command, hits); if (NULL != job) { - *hits = pcrs_execute(job, subject, size, &result, &size); + *hits = pcrs_execute(job, subject, buffer_size, &result, &new_size); if (*hits < 0) { freez(result); @@ -1055,7 +1196,6 @@ char *pcrs_execute_single_command(const char *subject, const char *pcrs_command, } -static const char warning[] = "... [too long, truncated]"; /********************************************************************* * * Function : pcrs_compile_dynamic_command @@ -1064,13 +1204,12 @@ static const char warning[] = "... [too long, truncated]"; * values of the variables and compiles it. * * Parameters : - * 1 : csp = Current client state (buffers, headers, etc...) - * 2 : pcrs_command = The dynamic pcrs command to compile - * 3 : v = NULL terminated array of variables and their values. - * 4 : error = pcrs error code + * 1 : pcrs_command = The dynamic pcrs command to compile + * 2 : v = NULL terminated array of variables and their values. + * 3 : error = pcrs error code * * Returns : NULL in case of hard errors, otherwise the - * compiled pcrs job. + * compiled pcrs job. * *********************************************************************/ pcrs_job *pcrs_compile_dynamic_command(char *pcrs_command, const struct pcrs_variable v[], int *error) @@ -1103,6 +1242,7 @@ pcrs_job *pcrs_compile_dynamic_command(char *pcrs_command, const struct pcrs_var { /* No proper delimiter found */ *error = PCRS_ERR_CMDSYNTAX; + freez(pcrs_command_tmp); return NULL; } @@ -1112,7 +1252,7 @@ pcrs_job *pcrs_compile_dynamic_command(char *pcrs_command, const struct pcrs_var */ assert(NULL == strchr(v->name, d)); - ret = snprintf(buf, sizeof(buf), "s%c\\$%s%c%s%cgT", d, v->name, d, v->value, d); + ret = snprintf(buf, sizeof(buf), "s%c\\$%s%c%s%cDgT", d, v->name, d, v->value, d); assert(ret >= 0); if (ret >= sizeof(buf)) { @@ -1122,10 +1262,11 @@ pcrs_job *pcrs_compile_dynamic_command(char *pcrs_command, const struct pcrs_var * with a truncation message and close the pattern * properly. */ - const size_t trailer_size = sizeof(warning) + 3; /* 3 for d + "gT" */ + static const char warning[] = "... [too long, truncated]"; + const size_t trailer_size = sizeof(warning) + 4; /* 4 for d + "DgT" */ char *trailer_start = buf + sizeof(buf) - trailer_size; - ret = snprintf(trailer_start, trailer_size, "%s%cgT", warning, d); + ret = snprintf(trailer_start, trailer_size, "%s%cDgT", warning, d); assert(ret == trailer_size - 1); assert(sizeof(buf) == strlen(buf) + 1); truncation = 1;