]> granicus.if.org Git - php/commitdiff
Avoid reallocation in preg_replace() if nothing was replaced
authorDmitry Stogov <dmitry@zend.com>
Tue, 10 Feb 2015 10:30:25 +0000 (13:30 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 10 Feb 2015 10:30:25 +0000 (13:30 +0300)
ext/fileinfo/libmagic/funcs.c
ext/pcre/php_pcre.c
ext/pcre/php_pcre.h
ext/spl/spl_iterators.c
win32/sendmail.c

index 4df0a2a496b33be8b45a0982325235955a9d4e2c..82f4cd38cd69b2179fd1713f1b6b2f086c2e8df6 100644 (file)
@@ -457,7 +457,7 @@ file_replace(struct magic_set *ms, const char *pat, const char *rep)
        zval_ptr_dtor(&patt);
 
        ZVAL_STRING(&repl, rep);
-       res = php_pcre_replace_impl(pce, ms->o.buf, strlen(ms->o.buf), &repl, 0, -1, &rep_cnt);
+       res = php_pcre_replace_impl(pce, NULL, ms->o.buf, strlen(ms->o.buf), &repl, 0, -1, &rep_cnt);
 
        zval_ptr_dtor(&repl);
        if (NULL == res) {
index c255fd91740e0679dea9e9812ebee64eeda80a86..8a6ecb5817c7b5db73d0a96ecc2a3ddc5ba806f5 100644 (file)
@@ -998,6 +998,7 @@ static zend_string *preg_do_repl_func(zval *function, char *subject, int *offset
 /* {{{ php_pcre_replace
  */
 PHPAPI zend_string *php_pcre_replace(zend_string *regex,
+                                                         zend_string *subject_str,
                                                          char *subject, int subject_len,
                                                          zval *replace_val, int is_callable_replace,
                                                          int limit, int *replace_count)
@@ -1009,13 +1010,13 @@ PHPAPI zend_string *php_pcre_replace(zend_string *regex,
                return NULL;
        }
 
-       return php_pcre_replace_impl(pce, subject, subject_len, replace_val,
+       return php_pcre_replace_impl(pce, subject_str, subject, subject_len, replace_val,
                is_callable_replace, limit, replace_count);
 }
 /* }}} */
 
 /* {{{ php_pcre_replace_impl() */
-PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *replace_val,
+PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *subject_str, char *subject, int subject_len, zval *replace_val,
        int is_callable_replace, int limit, int *replace_count)
 {
        pcre_extra              *extra = pce->extra;/* Holds results of studying */
@@ -1084,8 +1085,8 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject,
                }
        }
 
-       alloc_len = 2 * subject_len;
-       result = zend_string_alloc(alloc_len * sizeof(char), 0);
+       alloc_len = 0;
+       result = NULL;
 
        /* Initialize */
        match = NULL;
@@ -1148,9 +1149,17 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject,
                                }
                        }
 
-                       if (new_len > alloc_len) {
-                               alloc_len = alloc_len + 2 * new_len;
-                               result = zend_string_realloc(result, alloc_len, 0);
+                       if (new_len >= alloc_len) {
+                               if (alloc_len == 0) {
+                                       alloc_len = 2 * subject_len;
+                                       if (new_len >= alloc_len) {
+                                               alloc_len = alloc_len + 2 * new_len;
+                                       }
+                                       result = zend_string_alloc(alloc_len, 0);
+                               } else {
+                                       alloc_len = alloc_len + 2 * new_len;
+                                       result = zend_string_realloc(result, alloc_len, 0);
+                               }
                        }
                        /* copy the part of the string before the match */
                        memcpy(&result->val[result_len], piece, match-piece);
@@ -1205,6 +1214,10 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject,
                                memcpy(&result->val[result_len], piece, 1);
                                result_len++;
                        } else {
+                               if (!result && subject_str) {
+                                       result = zend_string_copy(subject_str);
+                                       break;
+                               }
                                new_len = result_len + subject_len - start_offset;
                                if (new_len > alloc_len) {
                                        alloc_len = new_len; /* now we know exactly how long it is */
@@ -1214,12 +1227,15 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject,
                                memcpy(&result->val[result_len], piece, subject_len - start_offset);
                                result_len += subject_len - start_offset;
                                result->val[result_len] = '\0';
+                               result->len = result_len;
                                break;
                        }
                } else {
                        pcre_handle_exec_error(count);
-                       zend_string_free(result);
-                       result = NULL;
+                       if (result) {
+                               zend_string_free(result);
+                               result = NULL;
+                       }
                        break;
                }
 
@@ -1233,9 +1249,6 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject,
                start_offset = offsets[1];
        }
 
-       if (result) {
-               result->len = result_len;
-       }
        if (size_offsets <= 32) {
                free_alloca(offsets, use_heap);
        } else {
@@ -1300,6 +1313,7 @@ static zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *sub
                        /* Do the actual replacement and put the result back into subject_str
                           for further replacements. */
                        if ((result = php_pcre_replace(regex_str,
+                                                                                  subject_str,
                                                                                   subject_str->val,
                                                                                   (int)subject_str->len,
                                                                                   replace_value,
@@ -1320,6 +1334,7 @@ static zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *sub
                return subject_str;
        } else {
                result = php_pcre_replace(Z_STR_P(regex),
+                                                                 subject_str,
                                                                  subject_str->val,
                                                                  (int)subject_str->len,
                                                                  replace,
index dc923fe62f625239ecff254092025128822fe375..88f810493ff0064b13e3c9e7865ae3524d40f4d2 100644 (file)
@@ -33,7 +33,7 @@
 #include <locale.h>
 #endif
 
-PHPAPI zend_string *php_pcre_replace(zend_string *regex, char *subject, int subject_len, zval *replace_val, int is_callable_replace, int limit, int *replace_count);
+PHPAPI zend_string *php_pcre_replace(zend_string *regex, zend_string *subject_str, char *subject, int subject_len, zval *replace_val, int is_callable_replace, int limit, int *replace_count);
 PHPAPI pcre* pcre_get_compiled_regex(zend_string *regex, pcre_extra **extra, int *options);
 PHPAPI pcre* pcre_get_compiled_regex_ex(zend_string *regex, pcre_extra **extra, int *preg_options, int *coptions);
 
@@ -59,7 +59,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex);
 PHPAPI void  php_pcre_match_impl(  pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value,
        zval *subpats, int global, int use_flags, zend_long flags, zend_long start_offset);
 
-PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value,
+PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *subject_str, char *subject, int subject_len, zval *return_value,
        int is_callable_replace, int limit, int *replace_count);
 
 PHPAPI void  php_pcre_split_impl(  pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value,
index bb7424a395fb407ab7b6694e91bcbfc74bd83c5a..21b3c8c905cf60dba41b4b7d16bdfc408f0c96ff 100644 (file)
@@ -2028,10 +2028,9 @@ SPL_METHOD(CallbackFilterIterator, accept)
 SPL_METHOD(RegexIterator, accept)
 {
        spl_dual_it_object *intern;
-       char *subject;
-       zend_string *result;
-       int subject_len, use_copy, count = 0;
-       zval *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement, rv;
+       zend_string *result, *subject;
+       int count = 0;
+       zval zcount, *replacement, tmp_replacement, rv;
 
        if (zend_parse_parameters_none() == FAILURE) {
                return;
@@ -2046,51 +2045,40 @@ SPL_METHOD(RegexIterator, accept)
        }
 
        if (intern->u.regex.flags & REGIT_USE_KEY) {
-               subject_ptr = &intern->current.key;
+               subject = zval_get_string(&intern->current.key);
        } else {
-               subject_ptr = &intern->current.data;
+               subject = zval_get_string(&intern->current.data);
        }
 
-       ZVAL_UNDEF(&subject_copy);
-       use_copy = zend_make_printable_zval(subject_ptr, &subject_copy);
-       if (use_copy) {
-               subject = Z_STRVAL(subject_copy);
-               subject_len = (int)Z_STRLEN(subject_copy);
-       } else {
-               subject = Z_STRVAL_P(subject_ptr);
-               subject_len = (int)Z_STRLEN_P(subject_ptr);
-       }
-
-       use_copy = 0;
        switch (intern->u.regex.mode)
        {
                case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
                case REGIT_MODE_MATCH:
-                       count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
+                       count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject->val, subject->len, 0, 0, NULL, 0);
                        RETVAL_BOOL(count >= 0);
                        break;
 
                case REGIT_MODE_ALL_MATCHES:
                case REGIT_MODE_GET_MATCH:
-                       if (!use_copy) {
-                               subject = estrndup(subject, subject_len);
-                               use_copy = 1;
-                       }
+//???                  if (!use_copy) {
+//???                          subject = estrndup(subject, subject_len);
+//???                          use_copy = 1;
+//???                  }
                        zval_ptr_dtor(&intern->current.data);
                        ZVAL_UNDEF(&intern->current.data);
-                       php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount,
+                       php_pcre_match_impl(intern->u.regex.pce, subject->val, subject->len, &zcount,
                                &intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0);
                        RETVAL_BOOL(Z_LVAL(zcount) > 0);
                        break;
 
                case REGIT_MODE_SPLIT:
-                       if (!use_copy) {
-                               subject = estrndup(subject, subject_len);
-                               use_copy = 1;
-                       }
+//???                  if (!use_copy) {
+//???                          subject = estrndup(subject, subject_len);
+//???                          use_copy = 1;
+//???                  }
                        zval_ptr_dtor(&intern->current.data);
                        ZVAL_UNDEF(&intern->current.data);
-                       php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, &intern->current.data, -1, intern->u.regex.preg_flags);
+                       php_pcre_split_impl(intern->u.regex.pce, subject->val, subject->len, &intern->current.data, -1, intern->u.regex.preg_flags);
                        count = zend_hash_num_elements(Z_ARRVAL(intern->current.data));
                        RETVAL_BOOL(count > 1);
                        break;
@@ -2103,7 +2091,7 @@ SPL_METHOD(RegexIterator, accept)
                                convert_to_string(&tmp_replacement);
                                replacement = &tmp_replacement;
                        }
-                       result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, -1, &count);
+                       result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject->val, subject->len, replacement, 0, -1, &count);
 
                        if (intern->u.regex.flags & REGIT_USE_KEY) {
                                zval_ptr_dtor(&intern->current.key);
@@ -2122,13 +2110,7 @@ SPL_METHOD(RegexIterator, accept)
        if (intern->u.regex.flags & REGIT_INVERTED) {
                RETVAL_BOOL(Z_TYPE_P(return_value) != IS_TRUE);
        }
-
-       if (use_copy) {
-               efree(subject);
-       }
-       if (!Z_ISUNDEF(subject_copy)) {
-               zval_ptr_dtor(&subject_copy);
-       }
+       zend_string_release(subject);
 } /* }}} */
 
 /* {{{ proto string RegexIterator::getRegex()
index 0254d82ee907e32a5c305c7b79a999d533ebaa4f..fd7424dda7306198fa55f1081b09e5e31a054a3d 100644 (file)
@@ -168,15 +168,16 @@ static zend_string *php_win32_mail_trim_header(char *header)
        regex = zend_string_init(PHP_WIN32_MAIL_UNIFY_PATTERN, sizeof(PHP_WIN32_MAIL_UNIFY_PATTERN)-1, 0);
 
        result = php_pcre_replace(regex,
-                                 header, (int)strlen(header),
+                                 NULL, header, (int)strlen(header),
                                  &replace,
                                  0,
                                  -1,
                                  NULL);
 
+       zval_ptr_dtor(&replace);
+       zend_string_release(regex);
+
        if (NULL == result) {
-               zval_ptr_dtor(&replace);
-               zend_string_free(regex);
                return NULL;
        }
 
@@ -184,12 +185,16 @@ static zend_string *php_win32_mail_trim_header(char *header)
        regex = zend_string_init(PHP_WIN32_MAIL_RMVDBL_PATTERN, sizeof(PHP_WIN32_MAIL_RMVDBL_PATTERN)-1, 0);
 
        result2 = php_pcre_replace(regex,
-                                  result->val, (int)result->len,
+                                  result, result->val, (int)result->len,
                                   &replace,
                                  0,
                                  -1,
                                  NULL);
-       return result;
+       zval_ptr_dtor(&replace);
+       zend_string_release(regex);
+       zend_string_release(result);
+
+       return result2;
 #else
        /* In case we don't have PCRE support (for whatever reason...) simply do nothing and return the unmodified header */
        return estrdup(header);