summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-02-10 13:30:25 +0300
committerDmitry Stogov <dmitry@zend.com>2015-02-10 13:30:25 +0300
commit4241a090ada5563c89d9926897b47c0411689816 (patch)
treed127982eff2be339c3c8ad5fa6b1ba8cd4e2b333
parent0be776b1fe0b00923378bfb8b9730209265a10d5 (diff)
downloadphp-git-4241a090ada5563c89d9926897b47c0411689816.tar.gz
Avoid reallocation in preg_replace() if nothing was replaced
-rw-r--r--ext/fileinfo/libmagic/funcs.c2
-rw-r--r--ext/pcre/php_pcre.c39
-rw-r--r--ext/pcre/php_pcre.h4
-rw-r--r--ext/spl/spl_iterators.c54
-rw-r--r--win32/sendmail.c15
5 files changed, 58 insertions, 56 deletions
diff --git a/ext/fileinfo/libmagic/funcs.c b/ext/fileinfo/libmagic/funcs.c
index 4df0a2a496..82f4cd38cd 100644
--- a/ext/fileinfo/libmagic/funcs.c
+++ b/ext/fileinfo/libmagic/funcs.c
@@ -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) {
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index c255fd9174..8a6ecb5817 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -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,
diff --git a/ext/pcre/php_pcre.h b/ext/pcre/php_pcre.h
index dc923fe62f..88f810493f 100644
--- a/ext/pcre/php_pcre.h
+++ b/ext/pcre/php_pcre.h
@@ -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,
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index bb7424a395..21b3c8c905 100644
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -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()
diff --git a/win32/sendmail.c b/win32/sendmail.c
index 0254d82ee9..fd7424dda7 100644
--- a/win32/sendmail.c
+++ b/win32/sendmail.c
@@ -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);