pcrs_compile_replacement(): Fix multiple segfaults and memory leaks
authorFabian Keil <fk@fabiankeil.de>
Sat, 24 Jan 2015 16:40:59 +0000 (16:40 +0000)
committerFabian Keil <fk@fabiankeil.de>
Sat, 24 Jan 2015 16:40:59 +0000 (16:40 +0000)
... and report errors more reliably. Previously some invalid
pcrs commands were silently accepted but didn't work as expected.

Partially discovered with afl-fuzz.

pcrs.c

diff --git a/pcrs.c b/pcrs.c
index d90b87c..4d11227 100644 (file)
--- a/pcrs.c
+++ b/pcrs.c
@@ -1,4 +1,4 @@
-const char pcrs_rcs[] = "$Id: pcrs.c,v 1.45 2014/10/18 11:27:04 fabiankeil Exp $";
+const char pcrs_rcs[] = "$Id: pcrs.c,v 1.46 2014/11/14 10:40:10 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/pcrs.c,v $
@@ -319,6 +319,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 +337,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;
                }
             }
 
@@ -360,14 +370,17 @@ static pcrs_substitute *pcrs_compile_replacement(const char *replacement, int tr
             }
 
             /* 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)
             {
                r->backref_count[r->backref[l]] += 1;
                r->block_offset[++l] = k;
             }
             else
             {
+               freez(text);
+               freez(r);
                *errptr = PCRS_WARN_BADREF;
+               return NULL;
             }
             continue;
          }