Put URL in error message
[privoxy.git] / pcrs.c
diff --git a/pcrs.c b/pcrs.c
index 89de9bc..0b746a1 100644 (file)
--- a/pcrs.c
+++ b/pcrs.c
@@ -1,4 +1,3 @@
-const char pcrs_rcs[] = "$Id: pcrs.c,v 1.41 2012/05/24 15:02:38 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/pcrs.c,v $
@@ -55,8 +54,6 @@ const char pcrs_rcs[] = "$Id: pcrs.c,v 1.41 2012/05/24 15:02:38 fabiankeil Exp $
 
 #include "pcrs.h"
 
-const char pcrs_h_rcs[] = PCRS_H_VERSION;
-
 /*
  * Internal prototypes
  */
@@ -80,6 +77,8 @@ static int              is_hex_sequence(const char *sequence);
  *********************************************************************/
 const char *pcrs_strerror(const int error)
 {
+   static char buf[100];
+
    if (error != 0)
    {
       switch (error)
@@ -119,7 +118,11 @@ const char *pcrs_strerror(const int error)
           * 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:
+            snprintf(buf, sizeof(buf),
+               "Error code %d. For details, check the pcre documentation.",
+               error);
+            return buf;
       }
    }
    /* error >= 0: No error */
@@ -176,6 +179,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 +238,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;
 
    /*
@@ -301,7 +339,7 @@ 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;
@@ -319,6 +357,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,7 +375,10 @@ 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;
                }
             }
 
@@ -359,15 +407,21 @@ 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;
          }
@@ -725,7 +779,7 @@ int pcrs_execute_list(pcrs_job *joblist, char *subject, size_t subject_length, c
  *          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
+ *          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.
@@ -747,19 +801,18 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char
    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);
    }
 
    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));
@@ -806,7 +859,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;
@@ -825,7 +877,7 @@ int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char
       else
          offset = offsets[1];
    }
-   /* Pass pcre error through if (bad) failiure */
+   /* Pass pcre error through if (bad) failure */
    if (submatches < PCRE_ERROR_NOMATCH)
    {
       free(matches);
@@ -1102,6 +1154,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;
       }