fix bug #55856: preg_replace should fail on trailing garbage
authorStanislav Malyshev <stas@php.net>
Sat, 30 Jun 2012 23:31:26 +0000 (16:31 -0700)
committerStanislav Malyshev <stas@php.net>
Wed, 29 Aug 2012 04:59:20 +0000 (21:59 -0700)
NEWS
ext/pcre/php_pcre.c
ext/pcre/tests/null_bytes.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 770b160e97eae93d60b50253c8e6390371455462..a6c68a2935c2e70c75c99f0bffc4cb05f032952c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,10 @@ PHP                                                                        NEWS
 - Installation:
   . Fixed bug #62460 (php binaries installed as binary.dSYM). (Reeze Xia)
 
+- PCRE:
+  . Fixed bug #55856 (preg_replace should fail on trailing garbage). 
+    (reg dot php at alf dot nu)
+
 - PDO:
   . Fixed bug #62685 (Wrong return datatype in PDO::inTransaction()). (Laruence)
 
index c9d707280cdd3d5c04c6786100deb29b40a29c1f..f61364cde96192d78dacb4e5aee86d407b7a980a 100644 (file)
@@ -275,7 +275,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
           get to the end without encountering a delimiter. */
        while (isspace((int)*(unsigned char *)p)) p++;
        if (*p == 0) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty regular expression");
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, 
+                                                p < regex + regex_len ? "Null byte in regex" : "Empty regular expression");
                return NULL;
        }
        
@@ -292,21 +293,18 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
                delimiter = pp[5];
        end_delimiter = delimiter;
 
+       pp = p;
+
        if (start_delimiter == end_delimiter) {
                /* We need to iterate through the pattern, searching for the ending delimiter,
                   but skipping the backslashed delimiters.  If the ending delimiter is not
                   found, display a warning. */
-               pp = p;
                while (*pp != 0) {
                        if (*pp == '\\' && pp[1] != 0) pp++;
                        else if (*pp == delimiter)
                                break;
                        pp++;
                }
-               if (*pp == 0) {
-                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter);
-                       return NULL;
-               }
        } else {
                /* We iterate through the pattern, searching for the matching ending
                 * delimiter. For each matching starting delimiter, we increment nesting
@@ -314,7 +312,6 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
                 * reach the end of the pattern without matching, display a warning.
                 */
                int brackets = 1;       /* brackets nesting level */
-               pp = p;
                while (*pp != 0) {
                        if (*pp == '\\' && pp[1] != 0) pp++;
                        else if (*pp == end_delimiter && --brackets <= 0)
@@ -323,10 +320,17 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
                                brackets++;
                        pp++;
                }
-               if (*pp == 0) {
-                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", end_delimiter);
-                       return NULL;
+       }
+
+       if (*pp == 0) {
+               if (pp < regex + regex_len) {
+                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex");
+               } else if (start_delimiter == end_delimiter) {
+                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter);
+               } else {
+                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", delimiter);
                }
+               return NULL;
        }
        
        /* Make a copy of the actual pattern. */
@@ -337,7 +341,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
 
        /* Parse through the options, setting appropriate flags.  Display
           a warning if we encounter an unknown modifier. */    
-       while (*pp != 0) {
+       while (pp < regex + regex_len) {
                switch (*pp++) {
                        /* Perl compatible options */
                        case 'i':       coptions |= PCRE_CASELESS;              break;
@@ -368,7 +372,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
                                break;
 
                        default:
-                               php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]);
+                               if (pp[-1]) {
+                                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]);
+                               } else {
+                                       php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex");
+                               }
                                efree(pattern);
                                return NULL;
                }
diff --git a/ext/pcre/tests/null_bytes.phpt b/ext/pcre/tests/null_bytes.phpt
new file mode 100644 (file)
index 0000000..9a3f433
--- /dev/null
@@ -0,0 +1,42 @@
+--TEST--
+Zero byte test
+--FILE--
+<?php
+
+preg_match("\0//i", "");
+preg_match("/\0/i", "");
+preg_match("//\0i", "");
+preg_match("//i\0", "");
+preg_match("/\\\0/i", "");
+
+preg_match("\0[]i", "");
+preg_match("[\0]i", "");
+preg_match("[]\0i", "");
+preg_match("[]i\0", "");
+preg_match("[\\\0]i", "");
+
+preg_replace("/foo/e\0/i", "echo('Eek');", "");
+
+?>
+--EXPECTF--
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 3
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 4
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 5
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 6
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 7
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 9
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 10
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 11
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 12
+
+Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 13
+
+Warning: preg_replace(): Null byte in regex in %snull_bytes.php on line 15