diff options
author | George Peter Banyard <girgias@php.net> | 2020-06-22 16:29:59 +0200 |
---|---|---|
committer | George Peter Banyard <girgias@php.net> | 2020-07-09 14:17:19 +0200 |
commit | af1de148025197f4f9131c2f074ea9ce65b7b04d (patch) | |
tree | 267432b0a83dcce4f134b86cb8fb47252d125b48 /ext/pcre/php_pcre.c | |
parent | 9839752a9c364dcec6e3c6f15f25987498486171 (diff) | |
download | php-git-af1de148025197f4f9131c2f074ea9ce65b7b04d.tar.gz |
Use ZPP string|array union check in PCRE extension
Diffstat (limited to 'ext/pcre/php_pcre.c')
-rw-r--r-- | ext/pcre/php_pcre.c | 227 |
1 files changed, 113 insertions, 114 deletions
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 16ec75d02b..8138dd5e69 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -2060,48 +2060,46 @@ static zend_always_inline zend_string *php_pcre_replace_func(zend_string *regex, /* }}} */ /* {{{ php_pcre_replace_array */ -static zend_string *php_pcre_replace_array(HashTable *regex, zval *replace, zend_string *subject_str, size_t limit, size_t *replace_count) +static zend_string *php_pcre_replace_array(HashTable *regex, + zend_string *replace_str, HashTable *replace_ht, + zend_string *subject_str, size_t limit, size_t *replace_count) { zval *regex_entry; zend_string *result; - zend_string *replace_str, *tmp_replace_str; - if (Z_TYPE_P(replace) == IS_ARRAY) { + zend_string_addref(subject_str); + + if (replace_ht) { uint32_t replace_idx = 0; - HashTable *replace_ht = Z_ARRVAL_P(replace); /* For each entry in the regex array, get the entry */ ZEND_HASH_FOREACH_VAL(regex, regex_entry) { /* Make sure we're dealing with strings. */ zend_string *tmp_regex_str; zend_string *regex_str = zval_get_tmp_string(regex_entry, &tmp_regex_str); + zend_string *replace_entry_str, *tmp_replace_entry_str; zval *zv; /* Get current entry */ while (1) { if (replace_idx == replace_ht->nNumUsed) { - replace_str = ZSTR_EMPTY_ALLOC(); - tmp_replace_str = NULL; + replace_entry_str = ZSTR_EMPTY_ALLOC(); + tmp_replace_entry_str = NULL; break; } zv = &replace_ht->arData[replace_idx].val; replace_idx++; if (Z_TYPE_P(zv) != IS_UNDEF) { - replace_str = zval_get_tmp_string(zv, &tmp_replace_str); + replace_entry_str = zval_get_tmp_string(zv, &tmp_replace_entry_str); break; } } /* Do the actual replacement and put the result back into subject_str for further replacements. */ - result = php_pcre_replace(regex_str, - subject_str, - ZSTR_VAL(subject_str), - ZSTR_LEN(subject_str), - replace_str, - limit, - replace_count); - zend_tmp_string_release(tmp_replace_str); + result = php_pcre_replace(regex_str, subject_str, ZSTR_VAL(subject_str), + ZSTR_LEN(subject_str), replace_entry_str, limit, replace_count); + zend_tmp_string_release(tmp_replace_entry_str); zend_tmp_string_release(tmp_regex_str); zend_string_release_ex(subject_str, 0); subject_str = result; @@ -2111,7 +2109,7 @@ static zend_string *php_pcre_replace_array(HashTable *regex, zval *replace, zend } ZEND_HASH_FOREACH_END(); } else { - replace_str = Z_STR_P(replace); + ZEND_ASSERT(replace_str != NULL); /* For each entry in the regex array, get the entry */ ZEND_HASH_FOREACH_VAL(regex, regex_entry) { @@ -2121,13 +2119,8 @@ static zend_string *php_pcre_replace_array(HashTable *regex, zval *replace, zend /* Do the actual replacement and put the result back into subject_str for further replacements. */ - result = php_pcre_replace(regex_str, - subject_str, - ZSTR_VAL(subject_str), - ZSTR_LEN(subject_str), - replace_str, - limit, - replace_count); + result = php_pcre_replace(regex_str, subject_str, ZSTR_VAL(subject_str), + ZSTR_LEN(subject_str), replace_str, limit, replace_count); zend_tmp_string_release(tmp_regex_str); zend_string_release_ex(subject_str, 0); subject_str = result; @@ -2143,83 +2136,80 @@ static zend_string *php_pcre_replace_array(HashTable *regex, zval *replace, zend /* }}} */ /* {{{ php_replace_in_subject */ -static zend_always_inline zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *subject, size_t limit, size_t *replace_count) +static zend_always_inline zend_string *php_replace_in_subject( + zend_string *regex_str, HashTable *regex_ht, + zend_string *replace_str, HashTable *replace_ht, + zend_string *subject, size_t limit, size_t *replace_count) { zend_string *result; - zend_string *subject_str = zval_get_string(subject); - - if (Z_TYPE_P(regex) != IS_ARRAY) { - result = php_pcre_replace(Z_STR_P(regex), - subject_str, - ZSTR_VAL(subject_str), - ZSTR_LEN(subject_str), - Z_STR_P(replace), - limit, - replace_count); - zend_string_release_ex(subject_str, 0); + + if (regex_str) { + ZEND_ASSERT(replace_str != NULL); + result = php_pcre_replace(regex_str, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), + replace_str, limit, replace_count); } else { - result = php_pcre_replace_array(Z_ARRVAL_P(regex), - replace, - subject_str, - limit, - replace_count); + ZEND_ASSERT(regex_ht != NULL); + result = php_pcre_replace_array(regex_ht, replace_str, replace_ht, subject, + limit, replace_count); } return result; } /* }}} */ /* {{{ php_replace_in_subject_func */ -static zend_string *php_replace_in_subject_func(zval *regex, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *subject, size_t limit, size_t *replace_count, zend_long flags) +static zend_string *php_replace_in_subject_func(zend_string *regex_str, HashTable *regex_ht, + zend_fcall_info *fci, zend_fcall_info_cache *fcc, + zend_string *subject, size_t limit, size_t *replace_count, zend_long flags) { zend_string *result; - zend_string *subject_str = zval_get_string(subject); - if (Z_TYPE_P(regex) != IS_ARRAY) { + if (regex_str) { result = php_pcre_replace_func( - Z_STR_P(regex), subject_str, fci, fcc, limit, replace_count, flags); - zend_string_release_ex(subject_str, 0); + regex_str, subject, fci, fcc, limit, replace_count, flags); return result; } else { + /* If regex is an array */ zval *regex_entry; - /* If regex is an array */ + ZEND_ASSERT(regex_ht != NULL); + + zend_string_addref(subject); /* For each entry in the regex array, get the entry */ - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(regex), regex_entry) { + ZEND_HASH_FOREACH_VAL(regex_ht, regex_entry) { /* Make sure we're dealing with strings. */ - zend_string *tmp_regex_str; - zend_string *regex_str = zval_get_tmp_string(regex_entry, &tmp_regex_str); + zend_string *tmp_regex_entry_str; + zend_string *regex_entry_str = zval_get_tmp_string(regex_entry, &tmp_regex_entry_str); - /* Do the actual replacement and put the result back into subject_str + /* Do the actual replacement and put the result back into subject for further replacements. */ result = php_pcre_replace_func( - regex_str, subject_str, fci, fcc, limit, replace_count, flags); - zend_tmp_string_release(tmp_regex_str); - zend_string_release_ex(subject_str, 0); - subject_str = result; + regex_entry_str, subject, fci, fcc, limit, replace_count, flags); + zend_tmp_string_release(tmp_regex_entry_str); + zend_string_release(subject); + subject = result; if (UNEXPECTED(result == NULL)) { break; } } ZEND_HASH_FOREACH_END(); - return subject_str; + return subject; } } /* }}} */ /* {{{ preg_replace_func_impl */ -static size_t preg_replace_func_impl(zval *return_value, zval *regex, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *subject, zend_long limit_val, zend_long flags) +static size_t preg_replace_func_impl(zval *return_value, + zend_string *regex_str, HashTable *regex_ht, + zend_fcall_info *fci, zend_fcall_info_cache *fcc, + zend_string *subject_str, HashTable *subject_ht, zend_long limit_val, zend_long flags) { zend_string *result; size_t replace_count = 0; - if (Z_TYPE_P(regex) != IS_ARRAY) { - convert_to_string_ex(regex); - } - - if (Z_TYPE_P(subject) != IS_ARRAY) { + if (subject_str) { result = php_replace_in_subject_func( - regex, fci, fcc, subject, limit_val, &replace_count, flags); + regex_str, regex_ht, fci, fcc, subject_str, limit_val, &replace_count, flags); if (result != NULL) { RETVAL_STR(result); } else { @@ -2231,13 +2221,18 @@ static size_t preg_replace_func_impl(zval *return_value, zval *regex, zend_fcall zend_string *string_key; zend_ulong num_key; - array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(subject))); + ZEND_ASSERT(subject_ht != NULL); + + array_init_size(return_value, zend_hash_num_elements(subject_ht)); /* For each subject entry, convert it to string, then perform replacement and add the result to the return_value array. */ - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(subject), num_key, string_key, subject_entry) { + ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) { + zend_string *tmp_subject_entry_str; + zend_string *subject_entry_str = zval_get_tmp_string(subject_entry, &tmp_subject_entry_str); + result = php_replace_in_subject_func( - regex, fci, fcc, subject_entry, limit_val, &replace_count, flags); + regex_str, regex_ht, fci, fcc, subject_entry_str, limit_val, &replace_count, flags); if (result != NULL) { /* Add to return array */ ZVAL_STR(&zv, result); @@ -2247,6 +2242,7 @@ static size_t preg_replace_func_impl(zval *return_value, zval *regex, zend_fcall zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &zv); } } + zend_tmp_string_release(tmp_subject_entry_str); } ZEND_HASH_FOREACH_END(); } @@ -2255,9 +2251,15 @@ static size_t preg_replace_func_impl(zval *return_value, zval *regex, zend_fcall /* }}} */ /* {{{ preg_replace_common */ -static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) +static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, bool is_filter) { - zval *regex, *replace, *subject, *zcount = NULL; + zval *zcount = NULL; + zend_string *regex_str; + HashTable *regex_ht; + zend_string *replace_str; + HashTable *replace_ht; + zend_string *subject_str; + HashTable *subject_ht; zend_long limit = -1; size_t replace_count = 0; zend_string *result; @@ -2265,33 +2267,24 @@ static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) /* Get function parameters and do error-checking. */ ZEND_PARSE_PARAMETERS_START(3, 5) - Z_PARAM_ZVAL(regex) - Z_PARAM_ZVAL(replace) - Z_PARAM_ZVAL(subject) + Z_PARAM_STR_OR_ARRAY_HT(regex_str, regex_ht) + Z_PARAM_STR_OR_ARRAY_HT(replace_str, replace_ht) + Z_PARAM_STR_OR_ARRAY_HT(subject_str, subject_ht) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) Z_PARAM_ZVAL(zcount) ZEND_PARSE_PARAMETERS_END(); - if (Z_TYPE_P(replace) != IS_ARRAY) { - convert_to_string_ex(replace); - if (Z_TYPE_P(regex) != IS_ARRAY) { - convert_to_string_ex(regex); - } - } else { - if (Z_TYPE_P(regex) != IS_ARRAY) { - zend_argument_type_error(1, "must be of type array when argument #2 ($replace) is an array, %s given", zend_zval_type_name(regex)); - RETURN_THROWS(); - } + /* If replace is an array then the regex argument needs to also be an array */ + if (replace_ht && !regex_ht) { + zend_argument_type_error(1, "must be of type array when argument #2 ($replace) is an array, string given"); + RETURN_THROWS(); } - if (Z_TYPE_P(subject) != IS_ARRAY) { + if (subject_str) { old_replace_count = replace_count; - result = php_replace_in_subject(regex, - replace, - subject, - limit, - &replace_count); + result = php_replace_in_subject(regex_str, regex_ht, replace_str, replace_ht, + subject_str, limit, &replace_count); if (result != NULL) { if (!is_filter || replace_count > old_replace_count) { RETVAL_STR(result); @@ -2308,17 +2301,19 @@ static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) zend_string *string_key; zend_ulong num_key; - array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(subject))); + ZEND_ASSERT(subject_ht != NULL); + + array_init_size(return_value, zend_hash_num_elements(subject_ht)); /* For each subject entry, convert it to string, then perform replacement and add the result to the return_value array. */ - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(subject), num_key, string_key, subject_entry) { + ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) { old_replace_count = replace_count; - result = php_replace_in_subject(regex, - replace, - subject_entry, - limit, - &replace_count); + zend_string *tmp_subject_entry_str; + zend_string *subject_entry_str = zval_get_tmp_string(subject_entry, &tmp_subject_entry_str); + result = php_replace_in_subject(regex_str, regex_ht, replace_str, replace_ht, + subject_entry_str, limit, &replace_count); + if (result != NULL) { if (!is_filter || replace_count > old_replace_count) { /* Add to return array */ @@ -2332,6 +2327,7 @@ static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) zend_string_release_ex(result, 0); } } + zend_tmp_string_release(tmp_subject_entry_str); } ZEND_HASH_FOREACH_END(); } @@ -2344,14 +2340,18 @@ static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) /* {{{ Perform Perl-style regular expression replacement. */ PHP_FUNCTION(preg_replace) { - preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); } /* }}} */ /* {{{ Perform Perl-style regular expression replacement using replacement callback. */ PHP_FUNCTION(preg_replace_callback) { - zval *regex, *subject, *zcount = NULL; + zval *zcount = NULL; + zend_string *regex_str; + HashTable *regex_ht; + zend_string *subject_str; + HashTable *subject_ht; zend_long limit = -1, flags = 0; size_t replace_count; zend_fcall_info fci; @@ -2359,16 +2359,18 @@ PHP_FUNCTION(preg_replace_callback) /* Get function parameters and do error-checking. */ ZEND_PARSE_PARAMETERS_START(3, 6) - Z_PARAM_ZVAL(regex) + Z_PARAM_STR_OR_ARRAY_HT(regex_str, regex_ht) Z_PARAM_FUNC(fci, fcc) - Z_PARAM_ZVAL(subject) + Z_PARAM_STR_OR_ARRAY_HT(subject_str, subject_ht) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) Z_PARAM_ZVAL(zcount) Z_PARAM_LONG(flags) ZEND_PARSE_PARAMETERS_END(); - replace_count = preg_replace_func_impl(return_value, regex, &fci, &fcc, subject, limit, flags); + replace_count = preg_replace_func_impl(return_value, regex_str, regex_ht, + &fci, &fcc, + subject_str, subject_ht, limit, flags); if (zcount) { ZEND_TRY_ASSIGN_REF_LONG(zcount, replace_count); } @@ -2378,16 +2380,17 @@ PHP_FUNCTION(preg_replace_callback) /* {{{ Perform Perl-style regular expression replacement using replacement callback. */ PHP_FUNCTION(preg_replace_callback_array) { - zval regex, zv, *replace, *subject, *pattern, *zcount = NULL; + zval zv, *replace, *subject, *zcount = NULL; + HashTable *pattern; + zend_string *str_idx_regex; zend_long limit = -1, flags = 0; - zend_string *str_idx; size_t replace_count = 0; zend_fcall_info fci; zend_fcall_info_cache fcc; /* Get function parameters and do error-checking. */ ZEND_PARSE_PARAMETERS_START(2, 5) - Z_PARAM_ARRAY(pattern) + Z_PARAM_ARRAY_HT(pattern) Z_PARAM_ZVAL(subject) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) @@ -2398,10 +2401,8 @@ PHP_FUNCTION(preg_replace_callback_array) fci.size = sizeof(fci); fci.object = NULL; - ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pattern), str_idx, replace) { - if (str_idx) { - ZVAL_STR_COPY(®ex, str_idx); - } else { + ZEND_HASH_FOREACH_STR_KEY_VAL(pattern, str_idx_regex, replace) { + if (!str_idx_regex) { php_error_docref(NULL, E_WARNING, "Delimiter must not be alphanumeric or backslash"); zval_ptr_dtor(return_value); RETURN_NULL(); @@ -2409,25 +2410,23 @@ PHP_FUNCTION(preg_replace_callback_array) if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) { zend_string *callback_name = zend_get_callable_name(replace); - php_error_docref(NULL, E_WARNING, "'%s' is not a valid callback", ZSTR_VAL(callback_name)); + zend_type_error("'%s' is not a valid callback", ZSTR_VAL(callback_name)); zend_string_release_ex(callback_name, 0); - zval_ptr_dtor(®ex); - zval_ptr_dtor(return_value); - ZVAL_COPY(return_value, subject); - return; + RETURN_THROWS(); } ZVAL_COPY_VALUE(&fci.function_name, replace); - replace_count += preg_replace_func_impl(&zv, ®ex, &fci, &fcc, subject, limit, flags); + replace_count += preg_replace_func_impl(&zv, str_idx_regex, /* regex_ht */ NULL, &fci, &fcc, + Z_STR_P(subject), Z_ARRVAL_P(subject), + limit, flags); + if (subject != return_value) { subject = return_value; } else { zval_ptr_dtor(return_value); } - zval_ptr_dtor(®ex); - ZVAL_COPY_VALUE(return_value, &zv); if (UNEXPECTED(EG(exception))) { @@ -2445,7 +2444,7 @@ PHP_FUNCTION(preg_replace_callback_array) /* {{{ Perform Perl-style regular expression replacement and only return matches. */ PHP_FUNCTION(preg_filter) { - preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); } /* }}} */ |