From 83cdb89f8a6cbc656f2f95aeb6ce1c97691e197f Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 7 Jun 2019 11:36:39 +0300 Subject: [PATCH] Fixed bug #77135 (Extract with EXTR_SKIP should skip $this) --- NEWS | 6 +- ext/standard/array.c | 70 ++++++++---------- ext/standard/tests/array/bug77135.phpt | 99 ++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 44 deletions(-) create mode 100644 ext/standard/tests/array/bug77135.phpt diff --git a/NEWS b/NEWS index c065a39b8d6..44644166d7b 100644 --- a/NEWS +++ b/NEWS @@ -13,8 +13,6 @@ PHP NEWS - MySQLi: . Fixed bug #77956 (When mysqli.allow_local_infile = Off, use a meaningful error message). (Sjon Hortensius) - . Fixed bug #38546 (bindParam incorrect processing of bool types). - (camporter) - OpenSSL: . Fixed bug #78079 (openssl_encrypt_ccm.phpt fails with OpenSSL 1.1.1c). @@ -24,6 +22,10 @@ PHP NEWS . Fixed bug #78038 (Socket_select fails when resource array contains references). (Nikita) +- Standard: + . Fixed bug #77135 (Extract with EXTR_SKIP should skip $this). + (Craig Duncan, Dmitry) + - Zip: . Fixed bug #76345 (zip.h not found). (Michael Maroszek) diff --git a/ext/standard/array.c b/ext/standard/array.c index 61f0f98f79c..a5bcecb02c9 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1756,10 +1756,10 @@ static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_t if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) { + if (zend_string_equals_literal(var_name, "GLOBALS")) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { + if (zend_string_equals_literal(var_name, "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -1800,10 +1800,10 @@ static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) { + if (zend_string_equals_literal(var_name, "GLOBALS")) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { + if (zend_string_equals_literal(var_name, "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -1837,7 +1837,7 @@ static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_t if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { + if (zend_string_equals_literal(var_name, "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -1849,7 +1849,7 @@ static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_t if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - if (ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) { + if (zend_string_equals_literal(var_name, "GLOBALS")) { continue; } ZVAL_MAKE_REF(entry); @@ -1882,7 +1882,7 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { + if (zend_string_equals_literal(var_name, "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -1894,7 +1894,7 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - if (ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) { + if (zend_string_equals_literal(var_name, "GLOBALS")) { continue; } ZVAL_DEREF(entry); @@ -1939,7 +1939,7 @@ static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *s } php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1); if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -1992,7 +1992,7 @@ static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbo } php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1); if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2047,9 +2047,10 @@ static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol continue; } } +prefix: php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1); if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2074,12 +2075,8 @@ static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { - if (!exception_thrown) { - exception_thrown = 1; - zend_throw_error(NULL, "Cannot re-assign $this"); - } - continue; + if (zend_string_equals_literal(var_name, "this")) { + goto prefix; } ZVAL_MAKE_REF(entry); Z_ADDREF_P(entry); @@ -2118,9 +2115,10 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab continue; } } +prefix: php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1); if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2146,12 +2144,8 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { - if (!exception_thrown) { - exception_thrown = 1; - zend_throw_error(NULL, "Cannot re-assign $this"); - } - continue; + if (zend_string_equals_literal(var_name, "this")) { + goto prefix; } ZVAL_DEREF(entry); if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry); @@ -2184,7 +2178,7 @@ static zend_long php_extract_ref_prefix_all(zend_array *arr, zend_array *symbol_ zend_string_release(str); } if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2231,7 +2225,7 @@ static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_tabl zend_string_release(str); } if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2269,7 +2263,8 @@ static zend_long php_extract_ref_prefix_invalid(zend_array *arr, zend_array *sym ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, var_name, entry) { if (var_name) { - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name)) + || zend_string_equals_literal(var_name, "this")) { php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1); if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { zend_string_release(Z_STR(final_name)); @@ -2287,7 +2282,7 @@ static zend_long php_extract_ref_prefix_invalid(zend_array *arr, zend_array *sym continue; } } - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2323,7 +2318,8 @@ static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_ ZEND_HASH_FOREACH_KEY_VAL_IND(arr, num_key, var_name, entry) { if (var_name) { - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name)) + || zend_string_equals_literal(var_name, "this")) { php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1); if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { zend_string_release(Z_STR(final_name)); @@ -2341,7 +2337,7 @@ static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_ continue; } } - if (Z_STRLEN(final_name) == sizeof("this")-1 && !strcmp(Z_STRVAL(final_name), "this")) { + if (zend_string_equals_literal(Z_STR(final_name), "this")) { if (!exception_thrown) { exception_thrown = 1; zend_throw_error(NULL, "Cannot re-assign $this"); @@ -2370,7 +2366,6 @@ static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_ static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */ { - int exception_thrown = 0; zend_long count = 0; zend_string *var_name; zval *entry, *orig_var; @@ -2382,11 +2377,7 @@ static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { - if (!exception_thrown) { - exception_thrown = 1; - zend_throw_error(NULL, "Cannot re-assign $this"); - } + if (zend_string_equals_literal(var_name, "this")) { continue; } orig_var = zend_hash_find(symbol_table, var_name); @@ -2414,7 +2405,6 @@ static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) static zend_long php_extract_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */ { - int exception_thrown = 0; zend_long count = 0; zend_string *var_name; zval *entry, *orig_var; @@ -2426,11 +2416,7 @@ static zend_long php_extract_skip(zend_array *arr, zend_array *symbol_table) /* if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { continue; } - if (ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) { - if (!exception_thrown) { - exception_thrown = 1; - zend_throw_error(NULL, "Cannot re-assign $this"); - } + if (zend_string_equals_literal(var_name, "this")) { continue; } orig_var = zend_hash_find(symbol_table, var_name); diff --git a/ext/standard/tests/array/bug77135.phpt b/ext/standard/tests/array/bug77135.phpt new file mode 100644 index 00000000000..0b23d627662 --- /dev/null +++ b/ext/standard/tests/array/bug77135.phpt @@ -0,0 +1,99 @@ +--TEST-- +Test extract() with $this +--FILE-- + EXTR_OVERWRITE, + 'EXTR_SKIP' => EXTR_SKIP, + 'EXTR_PREFIX_SAME' => EXTR_PREFIX_SAME, + 'EXTR_PREFIX_ALL' => EXTR_PREFIX_ALL, + 'EXTR_PREFIX_INVALID' => EXTR_PREFIX_INVALID, + 'EXTR_IF_EXISTS' => EXTR_IF_EXISTS, + 'EXTR_PREFIX_IF_EXISTS' => EXTR_PREFIX_IF_EXISTS, + ]; + + foreach ($options as $name => $flags) { + echo "{$name}\n"; + + $this->handle($name, $flags); + $this->handle("{$name}_REFS", $flags | EXTR_REFS); + echo "\n"; + } + } + + private function handle(string $name, int $flags): void + { + $array = ["this" => "value"]; + + try { + $result = extract($array, $flags, "x"); + echo " extract() = {$result}\n"; + + echo " \$this = " . get_class($this) . "\n"; + echo " \$v_this = " . (isset($x_this) ? $x_this : "NULL") . "\n"; + } catch (\Throwable $e) { + echo " Exception: " . $e->getMessage() . "\n"; + } + } +} + +(new Extract)->run(); + +?> +--EXPECT-- +EXTR_OVERWRITE + Exception: Cannot re-assign $this + Exception: Cannot re-assign $this + +EXTR_SKIP + extract() = 0 + $this = Extract + $v_this = NULL + extract() = 0 + $this = Extract + $v_this = NULL + +EXTR_PREFIX_SAME + extract() = 1 + $this = Extract + $v_this = value + extract() = 1 + $this = Extract + $v_this = value + +EXTR_PREFIX_ALL + extract() = 1 + $this = Extract + $v_this = value + extract() = 1 + $this = Extract + $v_this = value + +EXTR_PREFIX_INVALID + extract() = 1 + $this = Extract + $v_this = value + extract() = 1 + $this = Extract + $v_this = value + +EXTR_IF_EXISTS + extract() = 0 + $this = Extract + $v_this = NULL + extract() = 0 + $this = Extract + $v_this = NULL + +EXTR_PREFIX_IF_EXISTS + extract() = 0 + $this = Extract + $v_this = NULL + extract() = 0 + $this = Extract + $v_this = NULL