]> granicus.if.org Git - php/commitdiff
fix bug #55871 - Interruption in substr_replace()
authorStanislav Malyshev <stas@php.net>
Mon, 2 Jan 2012 00:47:57 +0000 (00:47 +0000)
committerStanislav Malyshev <stas@php.net>
Mon, 2 Jan 2012 00:47:57 +0000 (00:47 +0000)
NEWS
ext/standard/string.c
ext/standard/tests/strings/bug55871.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index c1a4a6ec6fd451aa7d88daad37f9037a3a83eb67..6c35a362cb06b7594fb16e6449eab53be62a8974 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,12 +4,13 @@ PHP                                                                        NEWS
 - Core:
   . Fixed bug #60613 (Segmentation fault with $cls->{expr}() syntax). (Dmitry)
   . Fixed bug #60611 (Segmentation fault with Cls::{expr}() syntax). (Laruence)
+  . Fixed bug #55871 (Interruption in substr_replace()). (Stas)
 
 - SAPI:
-  . Fixed bug #54374 (Insufficient validating of upload name leading to 
-    corrupted $_FILES indices). (Stas, lekensteyn at gmail dot com)
   . Fixed bug #55500 (Corrupted $_FILES indices lead to security concern).
     (Stas)
+  . Fixed bug #54374 (Insufficient validating of upload name leading to 
+    corrupted $_FILES indices). (Stas, lekensteyn at gmail dot com)
 
 - CLI SAPI:
   . Fixed bug #60591 (Memory leak when access a non-exists file). (Laruence)
index 29833f54e87bb7f696c45cef2aefb6b4664556ec..ef89b9050dc547f2dc9e0ac708bd05f7f7df9f2a 100644 (file)
@@ -36,7 +36,7 @@
 #ifdef HAVE_MONETARY_H
 # include <monetary.h>
 #endif
-/* 
+/*
  * This define is here because some versions of libintl redefine setlocale
  * to point to libintl_setlocale.  That's a ridiculous thing to do as far
  * as I am concerned, but with this define and the subsequent undef we
@@ -89,7 +89,7 @@ void register_string_constants(INIT_FUNC_ARGS)
        REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
 
 #ifdef HAVE_LOCALECONV
-       /* If last members of struct lconv equal CHAR_MAX, no grouping is done */       
+       /* If last members of struct lconv equal CHAR_MAX, no grouping is done */
 
 /* This is bad, but since we are going to be hardcoding in the POSIX stuff anyway... */
 # ifndef HAVE_LIMITS_H
@@ -110,7 +110,7 @@ void register_string_constants(INIT_FUNC_ARGS)
        REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
 # endif
 #endif
-       
+
 }
 /* }}} */
 
@@ -132,14 +132,14 @@ static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *
        size_t i, j;
 
        result = (unsigned char *) safe_emalloc(oldlen * 2, sizeof(char), 1);
-       
+
        for (i = j = 0; i < oldlen; i++) {
                result[j++] = hexconvtab[old[i] >> 4];
                result[j++] = hexconvtab[old[i] & 15];
        }
        result[j] = '\0';
 
-       if (newlen) 
+       if (newlen)
                *newlen = oldlen * 2 * sizeof(char);
 
        return (char *)result;
@@ -178,8 +178,8 @@ static char *php_hex2bin(const unsigned char *old, const size_t oldlen, size_t *
                }
        }
        str[target_length] = '\0';
-       
-       if (newlen) 
+
+       if (newlen)
                *newlen = target_length;
 
        return (char *)str;
@@ -245,7 +245,7 @@ PHP_FUNCTION(bin2hex)
        }
 
        result = php_bin2hex((unsigned char *)data, datalen, &newlen);
-       
+
        if (!result) {
                RETURN_FALSE;
        }
@@ -267,7 +267,7 @@ PHP_FUNCTION(hex2bin)
        }
 
        result = php_hex2bin((unsigned char *)data, datalen, &newlen);
-       
+
        if (!result) {
                RETURN_FALSE;
        }
@@ -281,18 +281,18 @@ static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /
        char *s11, *s22;
        int len1, len2;
        long start = 0, len = 0;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &s11, &len1,
                                &s22, &len2, &start, &len) == FAILURE) {
                return;
        }
-       
+
        if (ZEND_NUM_ARGS() < 4) {
                len = len1;
        }
-       
+
        /* look at substr() function for more information */
-       
+
        if (start < 0) {
                start += len1;
                if (start < 0) {
@@ -301,14 +301,14 @@ static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /
        } else if (start > len1) {
                RETURN_FALSE;
        }
-       
+
        if (len < 0) {
                len += (len1 - start);
                if (len < 0) {
                        len = 0;
                }
        }
-       
+
        if (len > len1 - start) {
                len = len1 - start;
        }
@@ -328,7 +328,7 @@ static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /
                                                s11 + start + len /*str1_end*/,
                                                s22 + len2 /*str2_end*/));
        }
-       
+
 }
 /* }}} */
 
@@ -524,7 +524,7 @@ PHP_FUNCTION(nl_langinfo)
 {
        long item;
        char *value;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &item) == FAILURE) {
                return;
        }
@@ -712,12 +712,12 @@ PHP_FUNCTION(strcoll)
 {
        char *s1, *s2;
        int s1len, s2len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1len, &s2, &s2len) == FAILURE) {
                return;
        }
 
-       RETURN_LONG(strcoll((const char *) s1, 
+       RETURN_LONG(strcoll((const char *) s1,
                            (const char *) s2));
 }
 /* }}} */
@@ -725,7 +725,7 @@ PHP_FUNCTION(strcoll)
 
 /* {{{ php_charmask
  * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
- * it needs to be incrementing.  
+ * it needs to be incrementing.
  * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
  */
 static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
@@ -736,8 +736,8 @@ static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_
 
        memset(mask, 0, 256);
        for (end = input+len; input < end; input++) {
-               c=*input; 
-               if ((input+3 < end) && input[1] == '.' && input[2] == '.' 
+               c=*input;
+               if ((input+3 < end) && input[1] == '.' && input[2] == '.'
                                && input[3] >= c) {
                        memset(mask+c, 1, input[3] - c + 1);
                        input+=3;
@@ -758,7 +758,7 @@ static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
                                result = FAILURE;
                                continue;
-                       } 
+                       }
                        /* FIXME: better error (a..b..c is the only left possibility?) */
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
                        result = FAILURE;
@@ -827,11 +827,11 @@ static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
        char *str;
        char *what = NULL;
        int str_len, what_len = 0;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &what, &what_len) == FAILURE) {
                return;
        }
-       
+
        php_trim(str, str_len, what, what_len, return_value, mode TSRMLS_CC);
 }
 /* }}} */
@@ -1001,7 +1001,7 @@ PHP_FUNCTION(wordwrap)
 
 /* {{{ php_explode
  */
-PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit) 
+PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
 {
        char *p1, *p2, *endp;
 
@@ -1027,11 +1027,11 @@ PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
 
 /* {{{ php_explode_negative_limit
  */
-PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, long limit) 
+PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, long limit)
 {
 #define EXPLODE_ALLOC_STEP 64
        char *p1, *p2, *endp;
-       
+
        endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
 
        p1 = Z_STRVAL_P(str);
@@ -1055,11 +1055,11 @@ PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_valu
                        }
                        positions[found++] = p1 = p2 + Z_STRLEN_P(delim);
                } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL);
-               
+
                to_return = limit + found;
                /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
                for (i = 0;i < to_return;i++) { /* this checks also for to_return > 0 */
-                       add_next_index_stringl(return_value, positions[i], 
+                       add_next_index_stringl(return_value, positions[i],
                                        (positions[i+1] - Z_STRLEN_P(delim)) - positions[i],
                                        1
                                );
@@ -1078,11 +1078,11 @@ PHP_FUNCTION(explode)
        int str_len = 0, delim_len = 0;
        long limit = LONG_MAX; /* No limit */
        zval zdelim, zstr;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &delim, &delim_len, &str, &str_len, &limit) == FAILURE) {
                return;
        }
-       
+
        if (delim_len == 0) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
                RETURN_FALSE;
@@ -1093,7 +1093,7 @@ PHP_FUNCTION(explode)
        if (str_len == 0) {
                if (limit >= 0) {
                        add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
-               } 
+               }
                return;
        }
 
@@ -1115,7 +1115,7 @@ PHP_FUNCTION(explode)
 
 /* {{{ php_implode
  */
-PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC) 
+PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC)
 {
        zval         **tmp;
        HashPosition   pos;
@@ -1150,7 +1150,7 @@ PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC)
                                        smart_str_appendl(&implstr, "1", sizeof("1")-1);
                                }
                                break;
-                       
+
                        case IS_NULL:
                                break;
 
@@ -1180,7 +1180,7 @@ PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC)
                                smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
                                zval_dtor(&tmp_val);
                                break;
-                               
+
                }
 
                if (++i != numelems) {
@@ -1208,7 +1208,7 @@ PHP_FUNCTION(implode)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &arg1, &arg2) == FAILURE) {
                return;
        }
-       
+
        if (arg2 == NULL) {
                if (Z_TYPE_PP(arg1) != IS_ARRAY) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument must be an array");
@@ -1235,7 +1235,7 @@ PHP_FUNCTION(implode)
                        return;
                }
        }
-       
+
        php_implode(delim, arr, return_value TSRMLS_CC);
 
        if (arg2 == NULL) {
@@ -1244,22 +1244,22 @@ PHP_FUNCTION(implode)
 }
 /* }}} */
 
-#define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]   
+#define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
 
 /* {{{ proto string strtok([string str,] string token)
    Tokenize a string */
 PHP_FUNCTION(strtok)
-{              
+{
        char *str, *tok = NULL;
        int str_len, tok_len = 0;
        zval *zv;
-       
+
        char *token;
        char *token_end;
        char *p;
        char *pe;
        int skipped = 0;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &tok, &tok_len) == FAILURE) {
                return;
        }
@@ -1278,21 +1278,21 @@ PHP_FUNCTION(strtok)
                BG(strtok_last) = BG(strtok_string) = Z_STRVAL_P(zv);
                BG(strtok_len) = str_len;
        }
-       
+
        p = BG(strtok_last); /* Where we start to search */
        pe = BG(strtok_string) + BG(strtok_len);
 
        if (!p || p >= pe) {
                RETURN_FALSE;
        }
-       
+
        token = tok;
        token_end = token + tok_len;
 
        while (token < token_end) {
                STRTOK_TABLE(token++) = 1;
        }
-       
+
        /* Skip leading delimiters */
        while (STRTOK_TABLE(p)) {
                if (++p >= pe) {
@@ -1303,14 +1303,14 @@ PHP_FUNCTION(strtok)
                }
                skipped++;
        }
-       
-       /* We know at this place that *p is no delimiter, so skip it */ 
+
+       /* We know at this place that *p is no delimiter, so skip it */
        while (++p < pe) {
                if (STRTOK_TABLE(p)) {
-                       goto return_token;      
+                       goto return_token;
                }
        }
-       
+
        if (p - BG(strtok_last)) {
 return_token:
                RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped, 1);
@@ -1323,7 +1323,7 @@ return_token:
        /* Restore table -- usually faster then memset'ing the table on every invocation */
 restore:
        token = tok;
-       
+
        while (token < token_end) {
                STRTOK_TABLE(token++) = 0;
        }
@@ -1335,7 +1335,7 @@ restore:
 PHPAPI char *php_strtoupper(char *s, size_t len)
 {
        unsigned char *c, *e;
-       
+
        c = (unsigned char *)s;
        e = (unsigned char *)c+len;
 
@@ -1353,13 +1353,13 @@ PHP_FUNCTION(strtoupper)
 {
        char *arg;
        int arglen;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) {
                return;
        }
 
        arg = estrndup(arg, arglen);
-       php_strtoupper(arg, arglen);    
+       php_strtoupper(arg, arglen);
        RETURN_STRINGL(arg, arglen, 0);
 }
 /* }}} */
@@ -1369,7 +1369,7 @@ PHP_FUNCTION(strtoupper)
 PHPAPI char *php_strtolower(char *s, size_t len)
 {
        unsigned char *c, *e;
-       
+
        c = (unsigned char *)s;
        e = c+len;
 
@@ -1387,7 +1387,7 @@ PHP_FUNCTION(strtolower)
 {
        char *str;
        int arglen;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &arglen) == FAILURE) {
                return;
        }
@@ -1508,7 +1508,7 @@ PHP_FUNCTION(dirname)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
-       
+
        ret = estrndup(str, str_len);
        ret_len = php_dirname(ret, str_len);
 
@@ -1531,10 +1531,10 @@ PHP_FUNCTION(pathinfo)
        }
 
        have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
-       
+
        MAKE_STD_ZVAL(tmp);
        array_init(tmp);
-       
+
        if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
                ret = estrndup(path, path_len);
                php_dirname(ret, path_len);
@@ -1544,12 +1544,12 @@ PHP_FUNCTION(pathinfo)
                efree(ret);
                ret = NULL;
        }
-       
+
        if (have_basename) {
                php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
                add_assoc_stringl(tmp, "basename", ret, ret_len, 0);
        }
-       
+
        if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
                const char *p;
                int idx;
@@ -1565,7 +1565,7 @@ PHP_FUNCTION(pathinfo)
                        add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1);
                }
        }
-       
+
        if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
                const char *p;
                int idx;
@@ -1694,7 +1694,7 @@ PHP_FUNCTION(stristr)
        char *haystack_dup;
        char needle_char[2];
        zend_bool part = 0;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
                return;
        }
@@ -1727,7 +1727,7 @@ PHP_FUNCTION(stristr)
                        RETVAL_STRINGL(haystack, found_offset, 1);
                } else {
                        RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);
-               }                       
+               }
        } else {
                RETVAL_FALSE;
        }
@@ -1747,7 +1747,7 @@ PHP_FUNCTION(strstr)
        char needle_char[2];
        long found_offset;
        zend_bool part = 0;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
                return;
        }
@@ -1794,7 +1794,7 @@ PHP_FUNCTION(strpos)
        char  needle_char[2];
        long  offset = 0;
        int   haystack_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
                return;
        }
@@ -1878,9 +1878,9 @@ PHP_FUNCTION(stripos)
                }
                needle_char[0] = tolower(needle_char[0]);
                needle_char[1] = '\0';
-               found = php_memnstr(haystack_dup + offset, 
-                                                       needle_char, 
-                                                       sizeof(needle_char) - 1, 
+               found = php_memnstr(haystack_dup + offset,
+                                                       needle_char,
+                                                       sizeof(needle_char) - 1,
                                                        haystack_dup + haystack_len);
        }
 
@@ -2002,7 +2002,7 @@ PHP_FUNCTION(strripos)
        }
 
        if (needle_len == 1) {
-               /* Single character search can shortcut memcmps 
+               /* Single character search can shortcut memcmps
                   Can also avoid tolower emallocs */
                if (offset >= 0) {
                        if (offset > haystack_len) {
@@ -2083,7 +2083,7 @@ PHP_FUNCTION(strrchr)
        const char *found = NULL;
        long found_offset;
        int  haystack_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &haystack, &haystack_len, &needle) == FAILURE) {
                return;
        }
@@ -2116,7 +2116,7 @@ static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int c
        char *p, *q;
        int chunks; /* complete chunks! */
        int restlen;
-       int out_len; 
+       int out_len;
 
        chunks = srclen / chunklen;
        restlen = srclen - chunks * chunklen; /* srclen % chunklen */
@@ -2162,7 +2162,7 @@ static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int c
 
 /* {{{ proto string chunk_split(string str [, int chunklen [, string ending]])
    Returns split line */
-PHP_FUNCTION(chunk_split) 
+PHP_FUNCTION(chunk_split)
 {
        char *str;
        char *result;
@@ -2171,7 +2171,7 @@ PHP_FUNCTION(chunk_split)
        long chunklen = 76;
        int result_len;
        int str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &chunklen, &end, &endlen) == FAILURE) {
                return;
        }
@@ -2187,8 +2187,8 @@ PHP_FUNCTION(chunk_split)
                result = emalloc(result_len + 1);
                memcpy(result, str, str_len);
                memcpy(result + str_len, end, endlen);
-               result[result_len] = '\0'; 
-               RETURN_STRINGL(result, result_len, 0);  
+               result[result_len] = '\0';
+               RETURN_STRINGL(result, result_len, 0);
        }
 
        if (!str_len) {
@@ -2213,7 +2213,7 @@ PHP_FUNCTION(substr)
        long l = 0, f;
        int str_len;
        int argc = ZEND_NUM_ARGS();
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &str, &str_len, &f, &l) == FAILURE) {
                return;
        }
@@ -2227,7 +2227,7 @@ PHP_FUNCTION(substr)
        } else {
                l = str_len;
        }
-       
+
        if (f > str_len) {
                RETURN_FALSE;
        } else if (f < 0 && -f > str_len) {
@@ -2290,7 +2290,7 @@ PHP_FUNCTION(substr_replace)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &str, &repl, &from, &len) == FAILURE) {
                return;
        }
-       
+
        if (Z_TYPE_PP(str) != IS_ARRAY) {
                if (Z_ISREF_PP(str)) {
                        SEPARATE_ZVAL(str);
@@ -2324,20 +2324,20 @@ PHP_FUNCTION(substr_replace)
 
        if (Z_TYPE_PP(str) == IS_STRING) {
                if (
-                       (argc == 3 && Z_TYPE_PP(from) == IS_ARRAY) || 
+                       (argc == 3 && Z_TYPE_PP(from) == IS_ARRAY) ||
                        (argc == 4 && Z_TYPE_PP(from) != Z_TYPE_PP(len))
                ) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should be of same type - numerical or array ");
-                       RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);          
+                       RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
                }
                if (argc == 4 && Z_TYPE_PP(from) == IS_ARRAY) {
                        if (zend_hash_num_elements(Z_ARRVAL_PP(from)) != zend_hash_num_elements(Z_ARRVAL_PP(len))) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should have the same number of elements");
-                               RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);          
+                               RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
                        }
                }
        }
-       
+
        if (Z_TYPE_PP(str) != IS_ARRAY) {
                if (Z_TYPE_PP(from) != IS_ARRAY) {
                        int repl_len = 0;
@@ -2395,7 +2395,7 @@ PHP_FUNCTION(substr_replace)
                        RETURN_STRINGL(result, result_len, 0);
                } else {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented");
-                       RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);  
+                       RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
                }
        } else { /* str is array of strings */
                char *str_index = NULL;
@@ -2420,6 +2420,9 @@ PHP_FUNCTION(substr_replace)
                while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) {
                        zval *orig_str;
                        zval dummy;
+                       ulong refcount;
+                       int was_ref;
+
                        if(Z_TYPE_PP(tmp_str) != IS_STRING) {
                                dummy = **tmp_str;
                                orig_str = &dummy;
@@ -2428,6 +2431,9 @@ PHP_FUNCTION(substr_replace)
                        } else {
                                orig_str = *tmp_str;
                        }
+                       was_ref = Z_ISREF_P(orig_str);
+                       Z_UNSET_ISREF_P(orig_str);
+                       refcount = Z_REFCOUNT_P(orig_str);
 
                        if (Z_TYPE_PP(from) == IS_ARRAY) {
                                if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) {
@@ -2478,7 +2484,7 @@ PHP_FUNCTION(substr_replace)
                                } else {
                                        l = Z_STRLEN_P(orig_str);
                                }
-                       } else if (argc > 3) { 
+                       } else if (argc > 3) {
                                l = Z_LVAL_PP(len);
                        } else {
                                l = Z_STRLEN_P(orig_str);
@@ -2510,8 +2516,13 @@ PHP_FUNCTION(substr_replace)
                                                repl_str = *tmp_repl;
                                        }
 
+                                       if(Z_REFCOUNT_P(orig_str) != refcount) {
+                                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument was modified while replacing");
+                                               break;
+                                       }
+
                                        result_len += Z_STRLEN_P(repl_str);
-                                       zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);        
+                                       zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
                                        result = emalloc(result_len + 1);
 
                                        memcpy(result, Z_STRVAL_P(orig_str), f);
@@ -2522,7 +2533,7 @@ PHP_FUNCTION(substr_replace)
                                        }
                                } else {
                                        result = emalloc(result_len + 1);
-       
+
                                        memcpy(result, Z_STRVAL_P(orig_str), f);
                                        memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
                                }
@@ -2546,6 +2557,8 @@ PHP_FUNCTION(substr_replace)
 
                        if(Z_TYPE_PP(tmp_str) != IS_STRING) {
                                zval_dtor(orig_str);
+                       } else {
+                               Z_SET_ISREF_TO_P(orig_str, was_ref);
                        }
                        zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
                } /*while*/
@@ -2566,15 +2579,15 @@ PHP_FUNCTION(quotemeta)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &old, &old_len) == FAILURE) {
                return;
        }
-       
+
        old_end = old + old_len;
-               
+
        if (old == old_end) {
                RETURN_FALSE;
        }
-       
+
        str = safe_emalloc(2, old_len, 1);
-       
+
        for (p = old, q = str; p != old_end; p++) {
                c = *p;
                switch (c) {
@@ -2607,11 +2620,11 @@ PHP_FUNCTION(ord)
 {
        char *str;
        int   str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
-       
+
        RETURN_LONG((unsigned char) str[0]);
 }
 /* }}} */
@@ -2640,7 +2653,7 @@ PHP_FUNCTION(chr)
 
 /* {{{ php_ucfirst
    Uppercase the first character of the word in a native string */
-static void php_ucfirst(char *str) 
+static void php_ucfirst(char *str)
 {
        register char *r;
        r = str;
@@ -2654,7 +2667,7 @@ PHP_FUNCTION(ucfirst)
 {
        char *str;
        int  str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
@@ -2705,7 +2718,7 @@ PHP_FUNCTION(ucwords)
        char *str;
        register char *r, *r_end;
        int str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
@@ -2767,7 +2780,7 @@ static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *
        HashPosition hpos;
        smart_str result = {0};
        HashTable tmp_hash;
-       
+
        zend_hash_init(&tmp_hash, zend_hash_num_elements(hash), NULL, NULL, 0);
        zend_hash_internal_pointer_reset_ex(hash, &hpos);
        while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) {
@@ -2785,12 +2798,12 @@ static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *
                                if (len < minlen) {
                                        minlen = len;
                                }
-                               break; 
-                       
+                               break;
+
                        case HASH_KEY_IS_LONG:
                                Z_TYPE(ctmp) = IS_LONG;
                                Z_LVAL(ctmp) = num_key;
-                       
+
                                convert_to_string(&ctmp);
                                len = Z_STRLEN(ctmp);
                                zend_hash_add(&tmp_hash, Z_STRVAL(ctmp), len+1, entry, sizeof(zval*), NULL);
@@ -2820,7 +2833,7 @@ static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *
 
                for (len = maxlen; len >= minlen; len--) {
                        key[len] = 0;
-                       
+
                        if (zend_hash_find(&tmp_hash, key, len+1, (void**)&trans) == SUCCESS) {
                                char *tval;
                                int tlen;
@@ -2845,7 +2858,7 @@ static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *
                                        zval_dtor(&tmp);
                                }
                                break;
-                       } 
+                       }
                }
 
                if (! found) {
@@ -2863,16 +2876,16 @@ static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *
 /* {{{ proto string strtr(string str, string from[, string to])
    Translates characters in str using given translation tables */
 PHP_FUNCTION(strtr)
-{                                                              
+{
        zval **from;
        char *str, *to = NULL;
        int str_len, to_len = 0;
        int ac = ZEND_NUM_ARGS();
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &str, &str_len, &from, &to, &to_len) == FAILURE) {
                return;
        }
-       
+
        if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array");
                RETURN_FALSE;
@@ -2889,12 +2902,12 @@ PHP_FUNCTION(strtr)
                convert_to_string_ex(from);
 
                ZVAL_STRINGL(return_value, str, str_len, 1);
-               
+
                php_strtr(Z_STRVAL_P(return_value),
                                  Z_STRLEN_P(return_value),
                                  Z_STRVAL_PP(from),
                                  to,
-                                 MIN(Z_STRLEN_PP(from), 
+                                 MIN(Z_STRLEN_PP(from),
                                  to_len));
        }
 }
@@ -2907,22 +2920,22 @@ PHP_FUNCTION(strrev)
        char *str;
        char *e, *n, *p;
        int  str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
-       
+
        n = emalloc(str_len+1);
        p = n;
-       
+
        e = str + str_len;
-       
+
        while (--e>=str) {
                *p++ = *e;
        }
-       
+
        *p = '\0';
-       
+
        RETVAL_STRINGL(n, str_len, 0);
 }
 /* }}} */
@@ -2935,7 +2948,7 @@ static void php_similar_str(const char *txt1, int len1, const char *txt2, int le
        char *end1 = (char *) txt1 + len1;
        char *end2 = (char *) txt2 + len2;
        int l;
-       
+
        *max = 0;
        for (p = (char *) txt1; p < end1; p++) {
                for (q = (char *) txt2; q < end2; q++) {
@@ -2960,11 +2973,11 @@ static int php_similar_char(const char *txt1, int len1, const char *txt2, int le
        php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
        if ((sum = max)) {
                if (pos1 && pos2) {
-                       sum += php_similar_char(txt1, pos1, 
+                       sum += php_similar_char(txt1, pos1,
                                                                        txt2, pos2);
                }
                if ((pos1 + max < len1) && (pos2 + max < len2)) {
-                       sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, 
+                       sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
                                                                        txt2 + pos2 + max, len2 - pos2 - max);
                }
        }
@@ -2982,15 +2995,15 @@ PHP_FUNCTION(similar_text)
        int ac = ZEND_NUM_ARGS();
        int sim;
        int t1_len, t2_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) {
                return;
        }
-       
+
        if (ac > 2) {
                convert_to_double_ex(percent);
        }
-       
+
        if (t1_len + t2_len == 0) {
                if (ac > 2) {
                        Z_DVAL_PP(percent) = 0;
@@ -2998,8 +3011,8 @@ PHP_FUNCTION(similar_text)
 
                RETURN_LONG(0);
        }
-       
-       sim = php_similar_char(t1, t1_len, t2, t2_len); 
+
+       sim = php_similar_char(t1, t1_len, t2, t2_len);
 
        if (ac > 2) {
                Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
@@ -3082,7 +3095,7 @@ PHP_FUNCTION(addslashes)
 {
        char *str;
        int  str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
@@ -3092,8 +3105,8 @@ PHP_FUNCTION(addslashes)
        }
 
        RETURN_STRING(php_addslashes(str,
-                                    str_len, 
-                                    &Z_STRLEN_P(return_value), 0 
+                                    str_len,
+                                    &Z_STRLEN_P(return_value), 0
                                     TSRMLS_CC), 0);
 }
 /* }}} */
@@ -3104,7 +3117,7 @@ PHP_FUNCTION(stripcslashes)
 {
        char *str;
        int  str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
@@ -3120,7 +3133,7 @@ PHP_FUNCTION(stripslashes)
 {
        char *str;
        int  str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                return;
        }
@@ -3133,7 +3146,7 @@ PHP_FUNCTION(stripslashes)
 #ifndef HAVE_STRERROR
 /* {{{ php_strerror
  */
-char *php_strerror(int errnum) 
+char *php_strerror(int errnum)
 {
        extern int sys_nerr;
        extern char *sys_errlist[];
@@ -3184,8 +3197,8 @@ PHPAPI void php_stripcslashes(char *str, int *len)
                                                break;
                                        }
                                        /* break is left intentionally */
-                               default: 
-                                       i=0; 
+                               default:
+                                       i=0;
                                        while (source < end && *source >= '0' && *source <= '7' && i<3) {
                                                numtmp[i++] = *source++;
                                        }
@@ -3211,7 +3224,7 @@ PHPAPI void php_stripcslashes(char *str, int *len)
        *len = nlen;
 }
 /* }}} */
-                       
+
 /* {{{ php_addcslashes
  */
 PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int should_free, char *what, int wlength TSRMLS_DC)
@@ -3230,7 +3243,7 @@ PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int s
        php_charmask((unsigned char *)what, wlength, flags TSRMLS_CC);
 
        for (source = (char*)str, end = source + length, target = new_str; source < end; source++) {
-               c = *source; 
+               c = *source;
                if (flags[(unsigned char)c]) {
                        if ((unsigned char) c < 32 || (unsigned char) c > 126) {
                                *target++ = '\\';
@@ -3245,7 +3258,7 @@ PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int s
                                        default: target += sprintf(target, "%03o", (unsigned char) c);
                                }
                                continue;
-                       } 
+                       }
                        *target++ = '\\';
                }
                *target++ = c;
@@ -3274,7 +3287,7 @@ PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_f
        char *source, *target;
        char *end;
        int local_new_length;
-               
+
        if (!new_length) {
                new_length = &local_new_length;
        }
@@ -3286,7 +3299,7 @@ PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_f
        source = str;
        end = source + length;
        target = new_str;
-       
+
        while (source < end) {
                switch (*source) {
                        case '\0':
@@ -3300,12 +3313,12 @@ PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_f
                                /* break is missing *intentionally* */
                        default:
                                *target++ = *source;
-                               break;  
+                               break;
                }
 
                source++;
        }
-       
+
        *target = 0;
        *new_length = target - new_str;
        if (should_free) {
@@ -3329,7 +3342,7 @@ PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_l
        int char_count = 0;
        int replaced = 0;
        char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL;
-               
+
        if (case_sensitivity) {
                char *p = str, *e = p + len;
                while ((p = memchr(p, from, (e - p)))) {
@@ -3348,7 +3361,7 @@ PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_l
                ZVAL_STRINGL(result, str, len, 1);
                return 0;
        }
-       
+
        Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
        Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
        Z_TYPE_P(result) = IS_STRING;
@@ -3402,7 +3415,7 @@ PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len,
 
 /* {{{ php_str_to_str_ex
  */
-PHPAPI char *php_str_to_str_ex(char *haystack, int length, 
+PHPAPI char *php_str_to_str_ex(char *haystack, int length,
        char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int *replace_count)
 {
        char *new_str;
@@ -3574,11 +3587,11 @@ nothing_todo:
 
 /* {{{ php_str_to_str
  */
-PHPAPI char *php_str_to_str(char *haystack, int length, 
+PHPAPI char *php_str_to_str(char *haystack, int length,
        char *needle, int needle_len, char *str, int str_len, int *_new_length)
 {
        return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL);
-} 
+}
 /* }}} */
 
 /* {{{ php_str_replace_in_subject
@@ -3591,19 +3604,19 @@ static void php_str_replace_in_subject(zval *search, zval *replace, zval **subje
        char            *replace_value = NULL;
        int                      replace_len = 0;
 
-       /* Make sure we're dealing with strings. */     
+       /* Make sure we're dealing with strings. */
        convert_to_string_ex(subject);
        Z_TYPE_P(result) = IS_STRING;
        if (Z_STRLEN_PP(subject) == 0) {
                ZVAL_STRINGL(result, "", 0, 1);
                return;
        }
-       
+
        /* If search is an array */
        if (Z_TYPE_P(search) == IS_ARRAY) {
                /* Duplicate subject string for repeated replacement */
                MAKE_COPY_ZVAL(subject, result);
-               
+
                zend_hash_internal_pointer_reset(Z_ARRVAL_P(search));
 
                if (Z_TYPE_P(replace) == IS_ARRAY) {
@@ -3616,7 +3629,7 @@ static void php_str_replace_in_subject(zval *search, zval *replace, zval **subje
 
                /* For each entry in the search array, get the entry */
                while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) {
-                       /* Make sure we're dealing with strings. */     
+                       /* Make sure we're dealing with strings. */
                        SEPARATE_ZVAL(search_entry);
                        convert_to_string(*search_entry);
                        if (Z_STRLEN_PP(search_entry) == 0) {
@@ -3631,9 +3644,9 @@ static void php_str_replace_in_subject(zval *search, zval *replace, zval **subje
                        if (Z_TYPE_P(replace) == IS_ARRAY) {
                                /* Get current entry */
                                if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {
-                                       /* Make sure we're dealing with strings. */     
+                                       /* Make sure we're dealing with strings. */
                                        convert_to_string_ex(replace_entry);
-                                       
+
                                        /* Set replacement value to the one we got from array */
                                        replace_value = Z_STRVAL_PP(replace_entry);
                                        replace_len = Z_STRLEN_PP(replace_entry);
@@ -3645,7 +3658,7 @@ static void php_str_replace_in_subject(zval *search, zval *replace, zval **subje
                                        replace_len = 0;
                                }
                        }
-                       
+
                        if (Z_STRLEN_PP(search_entry) == 1) {
                                php_char_to_str_ex(Z_STRVAL_P(result),
                                                                Z_STRLEN_P(result),
@@ -3748,12 +3761,12 @@ static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensit
                                        add_index_zval(return_value, num_key, result);
                                        break;
                        }
-               
+
                        zend_hash_move_forward(Z_ARRVAL_PP(subject));
                }
        } else {        /* if subject is not an array */
                php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL);
-       }       
+       }
        if (argc > 3) {
                zval_dtor(*zcount);
                ZVAL_LONG(*zcount, count);
@@ -3790,11 +3803,11 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
        long max_chars=0;
        int begin, end, char_count, orig_begin;
        int str_len;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &max_chars) == FAILURE) {
                return;
        }
-       
+
        if (str_len == 0) {
                RETURN_FALSE;
        }
@@ -3814,7 +3827,7 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
        } else {
                block_type = _HEB_BLOCK_TYPE_ENG;
        }
-       
+
        do {
                if (block_type == _HEB_BLOCK_TYPE_HEB) {
                        while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
@@ -3884,7 +3897,7 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
        broken_str = (char *) emalloc(str_len+1);
        begin=end=str_len-1;
        target = broken_str;
-               
+
        while (1) {
                char_count=0;
                while ((!max_chars || char_count < max_chars) && begin > 0) {
@@ -3900,7 +3913,7 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
                }
                if (char_count == max_chars) { /* try to avoid breaking words */
                        int new_char_count=char_count, new_begin=begin;
-                       
+
                        while (new_char_count > 0) {
                                if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
                                        break;
@@ -3914,7 +3927,7 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
                        }
                }
                orig_begin=begin;
-               
+
                if (_isblank(heb_str[begin])) {
                        heb_str[begin]='\n';
                }
@@ -3978,14 +3991,14 @@ PHP_FUNCTION(nl2br)
        int             repl_cnt = 0;
        int             str_len;
        zend_bool       is_xhtml = 1;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &is_xhtml) == FAILURE) {
                return;
        }
-       
+
        tmp = str;
        end = str + str_len;
-       
+
        /* it is really faster to scan twice and allocate mem once instead of scanning once
           and constantly reallocing */
        while (tmp < end) {
@@ -4000,10 +4013,10 @@ PHP_FUNCTION(nl2br)
                        }
                        repl_cnt++;
                }
-               
+
                tmp++;
        }
-       
+
        if (repl_cnt == 0) {
                RETURN_STRINGL(str, str_len, 1);
        }
@@ -4030,7 +4043,7 @@ PHP_FUNCTION(nl2br)
                                }
 
                                *target++ = '>';
-                               
+
                                if ((*str == '\r' && *(str+1) == '\n') || (*str == '\n' && *(str+1) == '\r')) {
                                        *target++ = *str++;
                                }
@@ -4038,10 +4051,10 @@ PHP_FUNCTION(nl2br)
                        default:
                                *target++ = *str;
                }
-       
+
                str++;
        }
-       
+
        *target = '\0';
 
        RETURN_STRINGL(tmp, new_length, 0);
@@ -4063,7 +4076,7 @@ PHP_FUNCTION(strip_tags)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|Z", &str, &str_len, &allow) == FAILURE) {
                return;
        }
-       
+
        /* To maintain a certain BC, we allow anything for the second parameter and return original string */
        if (allow != NULL) {
                convert_to_string_ex(allow);
@@ -4092,14 +4105,14 @@ PHP_FUNCTION(setlocale)
 
 #ifdef HAVE_SETLOCALE
        if (Z_TYPE_PP(pcategory) == IS_LONG) {
-               convert_to_long_ex(pcategory);  
+               convert_to_long_ex(pcategory);
                cat = Z_LVAL_PP(pcategory);
        } else {
                /* FIXME: The following behaviour should be removed. */
                char *category;
-               
+
                php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "Passing locale category name as string is deprecated. Use the LC_* -constants instead");
-               
+
                convert_to_string_ex(pcategory);
                category = Z_STRVAL_PP(pcategory);
 
@@ -4121,10 +4134,10 @@ PHP_FUNCTION(setlocale)
                        cat = LC_TIME;
                } else {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid locale category name %s, must be one of LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, or LC_TIME", category);
-                       
+
                        if (args) {
                                efree(args);
-                       }                       
+                       }
                        RETURN_FALSE;
                }
        }
@@ -4132,7 +4145,7 @@ PHP_FUNCTION(setlocale)
        if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
                zend_hash_internal_pointer_reset(Z_ARRVAL_PP(args[0]));
        }
-       
+
        while (1) {
                if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
                        if (!zend_hash_num_elements(Z_ARRVAL_PP(args[0]))) {
@@ -4144,7 +4157,7 @@ PHP_FUNCTION(setlocale)
                }
 
                convert_to_string_ex(plocale);
-               
+
                if (!strcmp ("0", Z_STRVAL_PP(plocale))) {
                        loc = NULL;
                } else {
@@ -4169,7 +4182,7 @@ PHP_FUNCTION(setlocale)
                        }
                        RETURN_STRING(retval, 1);
                }
-               
+
                if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
                        if (zend_hash_move_forward(Z_ARRVAL_PP(args[0])) == FAILURE) break;
                } else {
@@ -4210,7 +4223,7 @@ PHP_FUNCTION(parse_str)
                sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
        } else  {
                zval ret;
-               
+
                array_init(&ret);
                sapi_module.treat_data(PARSE_STRING, res, &ret TSRMLS_CC);
                /* Clear out the array that was passed in. */
@@ -4224,10 +4237,10 @@ PHP_FUNCTION(parse_str)
 
 /* {{{ php_tag_find
  *
- * Check if tag is in a set of tags 
+ * Check if tag is in a set of tags
  *
  * states:
- * 
+ *
  * 0 start tag
  * 1 first non-whitespace char seen
  */
@@ -4239,13 +4252,13 @@ int php_tag_find(char *tag, int len, char *set) {
        if (len <= 0) {
                return 0;
        }
-       
+
        norm = emalloc(len+1);
 
        n = norm;
        t = tag;
        c = tolower(*t);
-       /* 
+       /*
           normalize the tag removing leading and trailing whitespace
           and turn any <a whatever...> into just <a> and any </tag>
           into <tag>
@@ -4273,9 +4286,9 @@ int php_tag_find(char *tag, int len, char *set) {
                                break;
                }
                c = tolower(*(++t));
-       }  
+       }
        *(n++) = '>';
-       *n = '\0'; 
+       *n = '\0';
        if (strstr(set, norm)) {
                done=1;
        } else {
@@ -4293,9 +4306,9 @@ PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, in
 /* }}} */
 
 /* {{{ php_strip_tags
-       A simple little state-machine to strip out html and php tags 
-       
+
+       A simple little state-machine to strip out html and php tags
+
        State 0 is the output state, State 1 means we are inside a
        normal html tag and state 2 means we are inside a php tag.
 
@@ -4384,7 +4397,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow,
                                } else if (state == 0) {
                                        *(rp++) = c;
                                }
-                               break;  
+                               break;
 
                        case ')':
                                if (state == 2) {
@@ -4402,7 +4415,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow,
                                } else if (state == 0) {
                                        *(rp++) = c;
                                }
-                               break;  
+                               break;
 
                        case '>':
                                if (depth) {
@@ -4433,14 +4446,14 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow,
                                                        tp = tbuf;
                                                }
                                                break;
-                                               
+
                                        case 2: /* PHP */
                                                if (!br && lc != '\"' && *(p-1) == '?') {
                                                        in_q = state = 0;
                                                        tp = tbuf;
                                                }
                                                break;
-                                               
+
                                        case 3:
                                                in_q = state = 0;
                                                tp = tbuf;
@@ -4488,10 +4501,10 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow,
                                        }
                                }
                                break;
-                       
-                       case '!': 
+
+                       case '!':
                                /* JavaScript & Other HTML scripting languages */
-                               if (state == 1 && *(p-1) == '<') { 
+                               if (state == 1 && *(p-1) == '<') {
                                        state = 3;
                                        lc = c;
                                } else {
@@ -4518,7 +4531,7 @@ PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow,
 
                        case '?':
 
-                               if (state == 1 && *(p-1) == '<') { 
+                               if (state == 1 && *(p-1) == '<') {
                                        br=0;
                                        state=2;
                                        break;
@@ -4563,12 +4576,12 @@ reg_char:
                                                tp = tbuf + pos;
                                        }
                                        *(tp++) = c;
-                               } 
+                               }
                                break;
                }
                c = *(++p);
                i++;
-       }       
+       }
        if (rp < rbuf + len) {
                *rp = '\0';
        }
@@ -4594,11 +4607,11 @@ PHP_FUNCTION(str_getcsv)
        char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL;
        int str_len = 0, delim_len = 0, enc_len = 0, esc_len = 0;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &str, &str_len, &delim_str, &delim_len, 
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &str, &str_len, &delim_str, &delim_len,
                &enc_str, &enc_len, &esc_str, &esc_len) == FAILURE) {
                return;
        }
-       
+
        delim = delim_len ? delim_str[0] : delim;
        enc = enc_len ? enc_str[0] : enc;
        esc = esc_len ? esc_str[0] : esc;
@@ -4616,7 +4629,7 @@ PHP_FUNCTION(str_repeat)
        long            mult;                   /* Multiplier */
        char            *result;                /* Resulting string */
        size_t          result_len;             /* Length of the resulting string */
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &input_str, &input_len, &mult) == FAILURE) {
                return;
        }
@@ -4631,13 +4644,13 @@ PHP_FUNCTION(str_repeat)
        if (input_len == 0 || mult == 0)
                RETURN_EMPTY_STRING();
 
-       /* Initialize the result string */      
+       /* Initialize the result string */
        result_len = input_len * mult;
        result = (char *)safe_emalloc(input_len, mult, 1);
-       
+
        /* Heavy optimization for situations where input string is 1 byte long */
        if (input_len == 1) {
-               memset(result, *(input_str), mult); 
+               memset(result, *(input_str), mult);
        } else {
                char *s, *e, *ee;
                int l=0;
@@ -4645,7 +4658,7 @@ PHP_FUNCTION(str_repeat)
                s = result;
                e = result + input_len;
                ee = result + result_len;
-               
+
                while (e<ee) {
                        l = (e-s) < (ee-e) ? (e-s) : (ee-e);
                        memmove(e, s, l);
@@ -4654,7 +4667,7 @@ PHP_FUNCTION(str_repeat)
        }
 
        result[result_len] = '\0';
-       
+
        RETURN_STRINGL(result, result_len, 0);
 }
 /* }}} */
@@ -4720,7 +4733,7 @@ PHP_FUNCTION(count_chars)
                                break;
                }
        }
-       
+
        if (mymode >= 3 && mymode <= 4) {
                RETURN_STRINGL(retstr, retlen, 1);
        }
@@ -4819,7 +4832,7 @@ PHP_FUNCTION(localeconv)
                struct lconv currlocdata;
 
                localeconv_r( &currlocdata );
-   
+
                /* Grab the grouping data out of the array */
                len = strlen(currlocdata.grouping);
 
@@ -4908,18 +4921,18 @@ PHP_FUNCTION(substr_count)
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring");
                RETURN_FALSE;
        }
-       
+
        p = haystack;
        endp = p + haystack_len;
 
        if (offset < 0) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater than or equal to 0");
-               RETURN_FALSE;           
+               RETURN_FALSE;
        }
 
        if (offset > haystack_len) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length", offset);
-               RETURN_FALSE;           
+               RETURN_FALSE;
        }
        p += offset;
 
@@ -4927,7 +4940,7 @@ PHP_FUNCTION(substr_count)
 
                if (length <= 0) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0");
-                       RETURN_FALSE;           
+                       RETURN_FALSE;
                }
                if (length > (haystack_len - offset)) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length", length);
@@ -4935,7 +4948,7 @@ PHP_FUNCTION(substr_count)
                }
                endp = p + length;
        }
-       
+
        if (needle_len == 1) {
                cmp = needle[0];
 
@@ -4952,7 +4965,7 @@ PHP_FUNCTION(substr_count)
 
        RETURN_LONG(count);
 }
-/* }}} */      
+/* }}} */
 
 /* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]])
    Returns input string padded on the left or right to specified length with pad_string */
@@ -4962,7 +4975,7 @@ PHP_FUNCTION(str_pad)
        char *input;                            /* Input string */
        int  input_len;
        long pad_length;                        /* Length to pad to */
-       
+
        /* Helper variables */
        size_t     num_pad_chars;               /* Number of padding characters (total - input size) */
        char  *result = NULL;           /* Resulting string */
@@ -4987,7 +5000,7 @@ PHP_FUNCTION(str_pad)
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding string cannot be empty");
                return;
        }
-       
+
        if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH");
                return;
@@ -4996,7 +5009,7 @@ PHP_FUNCTION(str_pad)
        num_pad_chars = pad_length - input_len;
        if (num_pad_chars >= INT_MAX) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding length is too long");
-               return; 
+               return;
        }
        result = (char *)emalloc(input_len + num_pad_chars + 1);
 
@@ -5035,7 +5048,7 @@ PHP_FUNCTION(str_pad)
        RETURN_STRINGL(result, result_len, 0);
 }
 /* }}} */
-   
+
 /* {{{ proto mixed sscanf(string str, string format [, string ...])
    Implements an ANSI C compatible sscanf */
 PHP_FUNCTION(sscanf)
@@ -5044,13 +5057,13 @@ PHP_FUNCTION(sscanf)
        char *str, *format;
        int str_len, format_len, result, num_args = 0;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss*", &str, &str_len, &format, &format_len, 
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss*", &str, &str_len, &format, &format_len,
                &args, &num_args) == FAILURE) {
                return;
        }
-       
+
        result = php_sscanf_internal(str, format, num_args, args, 0, &return_value TSRMLS_CC);
-       
+
        if (args) {
                efree(args);
        }
@@ -5088,13 +5101,13 @@ static void php_string_shuffle(char *str, long len TSRMLS_DC) /* {{{ */
        /* The implementation is stolen from array_data_shuffle       */
        /* Thus the characteristics of the randomization are the same */
        n_elems = len;
-       
+
        if (n_elems <= 1) {
                return;
        }
 
        n_left = n_elems;
-       
+
        while (--n_left) {
                rnd_idx = php_rand(TSRMLS_C);
                RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
@@ -5119,7 +5132,7 @@ PHP_FUNCTION(str_shuffle)
        }
 
        RETVAL_STRINGL(arg, arglen, 1);
-       if (Z_STRLEN_P(return_value) > 1) { 
+       if (Z_STRLEN_P(return_value) > 1) {
                php_string_shuffle(Z_STRVAL_P(return_value), (long) Z_STRLEN_P(return_value) TSRMLS_CC);
        }
 }
@@ -5131,7 +5144,7 @@ PHP_FUNCTION(str_shuffle)
        found inside the string. If format of 2 is specified, then the function
        will return an associated array where the position of the word is the key
        and the word itself is the value.
-       
+
        For the purpose of this function, 'word' is defined as a locale dependent
        string containing alphabetic characters, which also may contain, but not start
        with "'" and "-" characters.
@@ -5168,7 +5181,7 @@ PHP_FUNCTION(str_word_count)
        if (char_list) {
                php_charmask((unsigned char *)char_list, char_list_len, ch TSRMLS_CC);
        }
-       
+
        p = str;
        e = str + str_len;
 
@@ -5199,14 +5212,14 @@ PHP_FUNCTION(str_word_count)
                                        break;
                                default:
                                        word_count++;
-                                       break;          
+                                       break;
                        }
                }
                p++;
        }
-       
+
        if (!type) {
-               RETURN_LONG(word_count);                
+               RETURN_LONG(word_count);
        }
 }
 
@@ -5230,7 +5243,7 @@ PHP_FUNCTION(money_format)
        e = p + format_len;
        while ((p = memchr(p, '%', (e - p)))) {
                if (*(p + 1) == '%') {
-                       p += 2; 
+                       p += 2;
                } else if (!check) {
                        check = 1;
                        p++;
@@ -5262,7 +5275,7 @@ PHP_FUNCTION(str_split)
        long split_length = 1;
        char *p;
        int n_reg_segments;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &split_length) == FAILURE) {
                return;
        }
@@ -5300,14 +5313,14 @@ PHP_FUNCTION(strpbrk)
        char *haystack, *char_list;
        int haystack_len, char_list_len;
        char *p;
-       
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &haystack, &haystack_len, &char_list, &char_list_len) == FAILURE) {
                RETURN_FALSE;
        }
 
        if (!char_list_len) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "The character list cannot be empty");
-               RETURN_FALSE;   
+               RETURN_FALSE;
        }
 
        if ((p = strpbrk(haystack, char_list))) {
diff --git a/ext/standard/tests/strings/bug55871.phpt b/ext/standard/tests/strings/bug55871.phpt
new file mode 100644 (file)
index 0000000..7b743fd
--- /dev/null
@@ -0,0 +1,47 @@
+--TEST--
+Bug #55871 (Interruption in substr_replace())
+--FILE--
+<?php
+class test1 {
+       public function __toString() {
+               preg_match('//', '', $GLOBALS['my_var']);
+               return '';
+       }
+}
+
+class test2 {
+        public function __toString() {
+               $GLOBALS['my_var'] += 0x08048000;
+                return '';
+        }
+}
+
+class test3 {
+        public function __toString() {                
+                $GLOBALS['my_var'] .= "AAAAAAAA";
+                return '';
+        }
+}
+
+$my_var = str_repeat('A', 40);
+$out = substr_replace(array(&$my_var), array(new test1), 40, 0);
+var_dump($out);
+$my_var = str_repeat('A', 40);
+$out = substr_replace(array(&$my_var), array(new test2), 40, 0);
+var_dump($out);
+$my_var = str_repeat('A', 40);
+$out = substr_replace(array(&$my_var), array(new test3), 40, 0);
+var_dump($out);
+--EXPECTF--
+
+Warning: substr_replace(): Argument was modified while replacing in %s on line %d
+array(0) {
+}
+
+Warning: substr_replace(): Argument was modified while replacing in %s on line %d
+array(0) {
+}
+
+Warning: substr_replace(): Argument was modified while replacing in %s on line %d
+array(0) {
+}