diff --git a/NEWS b/NEWS index ac3381900831..eff542c0e46b 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,8 @@ PHP NEWS . Fixed bug GH-22046 (The unserialize function can lead to segfault when non-Serializable internal classes are serialized back with the C format). (kocsismate) + . Fixed bug GH-22292 (AST pretty printing does not correctly handle + invalid variable names). (timwolla) - BCMath: . Added NUL-byte validation to BCMath functions. (jorgsowa) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 43a81c87d4b7..1f24fb82fcf9 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -17,6 +17,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES . ZSTR_INIT_LITERAL(), zend_string_starts_with_literal(), and zend_string_starts_with_literal_ci() now support strings containing NUL bytes. Passing non-literal char* is no longer supported. + . Added zend_string_equals_cstr_ci(). . The misnamed ZVAL_IS_NULL() has been removed. Use Z_ISNULL() instead. . New zend_class_entry.ce_flags2 and zend_function.fn_flags2 fields were added, given the primary flags were running out of bits. @@ -103,6 +104,12 @@ PHP 8.6 INTERNALS UPGRADE NOTES . The deprecated Z_IMMUTABLE(), Z_IMMUTABLE_P(), Z_OPT_IMMUTABLE(), and Z_OPT_IMMUTABLE_P() macros have been removed. Check for IS_ARRAY && !REFCOUNTED directly. + . The unused Z_GC_*() macros have been removed. Use the corresponding + GC_*() macro on the result of Z_COUNTED(). + . The zend_binary_zval_strcmp() and zend_binary_zval_strncmp() functions + have been removed, because they are unsafe by relying on the zvals + having a specific type. Use zend_binary_strcmp() / zend_binary_strncmp(), + string_compare_function() or similar instead. . Added zend_fcall_info.consumed_args together with zend_fci_consumed_arg(), which allows moving a selected callback argument instead of copying it in zend_call_function(). Currently only a single diff --git a/Zend/tests/assert/expect_015.phpt b/Zend/tests/assert/expect_015.phpt index 9f8e9b77003b..79ea3703ead6 100644 --- a/Zend/tests/assert/expect_015.phpt +++ b/Zend/tests/assert/expect_015.phpt @@ -304,7 +304,7 @@ assert(0 && ($a = function (): ?static { $x = "{$a}b"; $x = "{$a}b"; $x = " {$foo->bar} {${$foo->bar}} "; - $x = " ${---} "; + $x = " ${'---'} "; foo(); \foo(); namespace\foo(); diff --git a/Zend/tests/debug_info/debug_info-error-0.0.phpt b/Zend/tests/debug_info/debug_info-error-0.0.phpt index ab41b440fc88..4df25c4c95af 100644 --- a/Zend/tests/debug_info/debug_info-error-0.0.phpt +++ b/Zend/tests/debug_info/debug_info-error-0.0.phpt @@ -17,4 +17,4 @@ $c = new C(0.0); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-0.phpt b/Zend/tests/debug_info/debug_info-error-0.phpt index 37289c6468ff..c0cedf3b88e5 100644 --- a/Zend/tests/debug_info/debug_info-error-0.phpt +++ b/Zend/tests/debug_info/debug_info-error-0.phpt @@ -17,4 +17,4 @@ $c = new C(0); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-1.0.phpt b/Zend/tests/debug_info/debug_info-error-1.0.phpt index 9b168621b5ef..6af945cb0e37 100644 --- a/Zend/tests/debug_info/debug_info-error-1.0.phpt +++ b/Zend/tests/debug_info/debug_info-error-1.0.phpt @@ -17,4 +17,4 @@ $c = new C(1.0); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-1.phpt b/Zend/tests/debug_info/debug_info-error-1.phpt index ae01a6055c00..7cadd485118d 100644 --- a/Zend/tests/debug_info/debug_info-error-1.phpt +++ b/Zend/tests/debug_info/debug_info-error-1.phpt @@ -17,4 +17,4 @@ $c = new C(1); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-case-insensitive.phpt b/Zend/tests/debug_info/debug_info-error-case-insensitive.phpt new file mode 100644 index 000000000000..c2a6f4357a5c --- /dev/null +++ b/Zend/tests/debug_info/debug_info-error-case-insensitive.phpt @@ -0,0 +1,20 @@ +--TEST-- +Testing __debugInfo() magic method declared with non-canonical case +--FILE-- +val; + } + public function __construct($val) { + $this->val = $val; + } +} + +$c = new C(1); +var_dump($c); +?> +--EXPECTF-- +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-empty_str.phpt b/Zend/tests/debug_info/debug_info-error-empty_str.phpt index bbab78cd8202..21611cc9bde5 100644 --- a/Zend/tests/debug_info/debug_info-error-empty_str.phpt +++ b/Zend/tests/debug_info/debug_info-error-empty_str.phpt @@ -17,4 +17,4 @@ $c = new C(""); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-false.phpt b/Zend/tests/debug_info/debug_info-error-false.phpt index 3e48372c420c..fb5a35c2d1e3 100644 --- a/Zend/tests/debug_info/debug_info-error-false.phpt +++ b/Zend/tests/debug_info/debug_info-error-false.phpt @@ -17,4 +17,4 @@ $c = new C(false); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-object.phpt b/Zend/tests/debug_info/debug_info-error-object.phpt index 42e073999908..5cdc6b289e62 100644 --- a/Zend/tests/debug_info/debug_info-error-object.phpt +++ b/Zend/tests/debug_info/debug_info-error-object.phpt @@ -17,4 +17,4 @@ $c = new C(new stdClass); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-resource.phpt b/Zend/tests/debug_info/debug_info-error-resource.phpt index ccacce7a74b4..1fc84fe83d87 100644 --- a/Zend/tests/debug_info/debug_info-error-resource.phpt +++ b/Zend/tests/debug_info/debug_info-error-resource.phpt @@ -19,4 +19,4 @@ $c = new C(fopen("data:text/plain,Foo", 'r')); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-str.phpt b/Zend/tests/debug_info/debug_info-error-str.phpt index 85d3f63b97e0..fe4201de1c9f 100644 --- a/Zend/tests/debug_info/debug_info-error-str.phpt +++ b/Zend/tests/debug_info/debug_info-error-str.phpt @@ -17,4 +17,4 @@ $c = new C("foo"); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/debug_info/debug_info-error-true.phpt b/Zend/tests/debug_info/debug_info-error-true.phpt index 3843c6a7a14a..12bb7329a856 100644 --- a/Zend/tests/debug_info/debug_info-error-true.phpt +++ b/Zend/tests/debug_info/debug_info-error-true.phpt @@ -17,4 +17,4 @@ $c = new C(true); var_dump($c); ?> --EXPECTF-- -Fatal error: __debuginfo() must return an array in %s on line %d +Fatal error: __debugInfo() must return an array in %s on line %d diff --git a/Zend/tests/magic_methods/stringable_automatic_implementation_case_insensitive.phpt b/Zend/tests/magic_methods/stringable_automatic_implementation_case_insensitive.phpt new file mode 100644 index 000000000000..7f4564794452 --- /dev/null +++ b/Zend/tests/magic_methods/stringable_automatic_implementation_case_insensitive.phpt @@ -0,0 +1,23 @@ +--TEST-- +Stringable is automatically implemented for __toString() declared with non-canonical case +--FILE-- +getInterfaceNames()); +var_dump((string) new Test); + +?> +--EXPECT-- +bool(true) +array(1) { + [0]=> + string(10) "Stringable" +} +string(3) "foo" diff --git a/Zend/tests/try/gh22280.phpt b/Zend/tests/try/gh22280.phpt new file mode 100644 index 000000000000..30944aff59a6 --- /dev/null +++ b/Zend/tests/try/gh22280.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-22280: goto to label before try/finally after try/catch +--FILE-- + +--EXPECT-- +try +finally +done diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 65834adbafff..46b62dcc7c47 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2809,18 +2809,18 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, zend_check_magic_method_public(ce, fptr); zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY); - } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) { + } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_LCNAME)) { zend_check_magic_method_args(2, ce, fptr, error_type); zend_check_magic_method_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr); zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY); - } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) { + } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_LCNAME)) { zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr); zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_STRING); - } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) { + } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_LCNAME)) { zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr); @@ -2829,18 +2829,18 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, zend_error(E_DEPRECATED, "Returning null from %s::__debugInfo() is deprecated, make the return type non-nullable and return an empty array instead", ZSTR_VAL(ce->name)); } - } else if (zend_string_equals_literal(lcname, "__serialize")) { + } else if (zend_string_equals_literal(lcname, ZEND_SERIALIZE_FUNC_NAME)) { zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr); zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY); - } else if (zend_string_equals_literal(lcname, "__unserialize")) { + } else if (zend_string_equals_literal(lcname, ZEND_UNSERIALIZE_FUNC_NAME)) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr); zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_ARRAY); zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); - } else if (zend_string_equals_literal(lcname, "__set_state")) { + } else if (zend_string_equals_literal(lcname, ZEND_SET_STATE_FUNC_NAME)) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr); @@ -2888,16 +2888,16 @@ ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, c } else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) { ce->__isset = fptr; ce->ce_flags |= ZEND_ACC_USE_GUARDS; - } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) { + } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_LCNAME)) { ce->__callstatic = fptr; - } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) { + } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_LCNAME)) { ce->__tostring = fptr; - } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) { + } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_LCNAME)) { ce->__debugInfo = fptr; ce->ce_flags |= ZEND_ACC_USE_GUARDS; - } else if (zend_string_equals_literal(lcname, "__serialize")) { + } else if (zend_string_equals_literal(lcname, ZEND_SERIALIZE_FUNC_NAME)) { ce->__serialize = fptr; - } else if (zend_string_equals_literal(lcname, "__unserialize")) { + } else if (zend_string_equals_literal(lcname, ZEND_UNSERIALIZE_FUNC_NAME)) { ce->__unserialize = fptr; } } @@ -3111,7 +3111,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend /* If not specified, add __toString() return type for compatibility with Stringable * interface. */ - if (scope && zend_string_equals_literal_ci(internal_function->function_name, "__tostring") && + if (scope && zend_string_equals_literal_ci(internal_function->function_name, ZEND_TOSTRING_FUNC_LCNAME) && !(internal_function->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { zend_error(E_CORE_WARNING, "%s::__toString() implemented without string return type", ZSTR_VAL(scope->name)); @@ -4096,6 +4096,52 @@ ZEND_API zend_string *zend_get_callable_name_ex(const zval *callable, const zend } /* }}} */ +static bool zend_fcc_function_handler_equals(const zend_function *func1, const zend_function *func2) /* {{{ */ +{ + if (func1 == func2) { + return true; + } + + const bool fake_closure1 = (func1->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0; + const bool fake_closure2 = (func2->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0; + + if (!fake_closure1 && !fake_closure2) { + return false; + } + if (((func1->common.fn_flags & ZEND_ACC_CLOSURE) && !fake_closure1) || + ((func2->common.fn_flags & ZEND_ACC_CLOSURE) && !fake_closure2)) { + return false; + } + if (func1->type != func2->type || + func1->common.scope != func2->common.scope || + !zend_string_equals(func1->common.function_name, func2->common.function_name)) { + return false; + } + + if (func1->type == ZEND_USER_FUNCTION) { + return func1->op_array.opcodes == func2->op_array.opcodes; + } + + return func1->internal_function.handler == func2->internal_function.handler; +} +/* }}} */ + +ZEND_API bool zend_fcc_closure_equals_ex(const zend_fcall_info_cache* a, const zend_fcall_info_cache* b) /* {{{ */ +{ + const zend_function *func1 = a->function_handler; + const zend_function *func2 = b->function_handler; + + if (a->closure && a->closure->ce == zend_ce_closure) { + func1 = zend_get_closure_method_def(a->closure); + } + if (b->closure && b->closure->ce == zend_ce_closure) { + func2 = zend_get_closure_method_def(b->closure); + } + + return zend_fcc_function_handler_equals(func1, func2); +} +/* }}} */ + ZEND_API zend_string *zend_get_callable_name(const zval *callable) /* {{{ */ { return zend_get_callable_name_ex(callable, NULL); diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 2487c8b632f2..593be26788d7 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -758,20 +758,27 @@ ZEND_API void zend_fcall_info_argn(zend_fcall_info *fci, uint32_t argc, ...); ZEND_API zend_result zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval, zval *args); /* Zend FCC API to store and handle PHP userland functions */ +ZEND_API bool zend_fcc_closure_equals_ex(const zend_fcall_info_cache* a, const zend_fcall_info_cache* b); + static zend_always_inline bool zend_fcc_equals(const zend_fcall_info_cache* a, const zend_fcall_info_cache* b) { + if (a->closure || b->closure) { + return a->object == b->object + && a->calling_scope == b->calling_scope + && a->called_scope == b->called_scope + && (a->closure == b->closure || zend_fcc_closure_equals_ex(a, b)) + ; + } if (UNEXPECTED((a->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && (b->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) { return a->object == b->object && a->calling_scope == b->calling_scope - && a->closure == b->closure && zend_string_equals(a->function_handler->common.function_name, b->function_handler->common.function_name) ; } return a->function_handler == b->function_handler && a->object == b->object && a->calling_scope == b->calling_scope - && a->closure == b->closure ; } diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index a7e26711cd17..983299c0a9d8 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1723,9 +1723,14 @@ static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int ind { if (ast->kind == ZEND_AST_ZVAL) { zval *zv = zend_ast_get_zval(ast); - if (Z_TYPE_P(zv) == IS_STRING && - zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) { - smart_str_append(str, Z_STR_P(zv)); + if (Z_TYPE_P(zv) == IS_STRING) { + if (zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) { + smart_str_append(str, Z_STR_P(zv)); + } else { + smart_str_appends(str, "{'"); + zend_ast_export_str(str, Z_STR_P(zv)); + smart_str_appends(str, "'}"); + } return; } } else if (ast->kind == ZEND_AST_VAR) { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 105f99d24171..7e9f7ceac8db 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8610,7 +8610,7 @@ static zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string } zend_add_magic_method(ce, (zend_function *) op_array, lcname); - if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME) + if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_LCNAME) && !(ce->ce_flags & ZEND_ACC_TRAIT)) { add_stringable_interface(ce); } @@ -8841,7 +8841,7 @@ static zend_op_array *zend_compile_func_decl_ex( } zend_compile_params(params_ast, return_type_ast, - is_method && zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0); + is_method && zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_LCNAME) ? IS_STRING : 0); if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) { zend_mark_function_as_generator(); zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0e31332c97f0..2351882a560d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -368,7 +368,7 @@ typedef struct _zend_oparray_context { #define ZEND_ACC_USES_THIS (1 << 17) /* | X | | */ /* | | | */ /* call through user function trampoline. e.g. | | | */ -/* __call, __callstatic | | | */ +/* __call, __callStatic | | | */ #define ZEND_ACC_CALL_VIA_TRAMPOLINE (1 << 18) /* | X | | */ /* | | | */ /* disable inline caching | | | */ @@ -1249,10 +1249,18 @@ END_EXTERN_C() #define ZEND_UNSET_FUNC_NAME "__unset" #define ZEND_ISSET_FUNC_NAME "__isset" #define ZEND_CALL_FUNC_NAME "__call" -#define ZEND_CALLSTATIC_FUNC_NAME "__callstatic" -#define ZEND_TOSTRING_FUNC_NAME "__tostring" +#define ZEND_CALLSTATIC_FUNC_NAME "__callStatic" +#define ZEND_CALLSTATIC_FUNC_LCNAME "__callstatic" +#define ZEND_TOSTRING_FUNC_NAME "__toString" +#define ZEND_TOSTRING_FUNC_LCNAME "__tostring" #define ZEND_INVOKE_FUNC_NAME "__invoke" -#define ZEND_DEBUGINFO_FUNC_NAME "__debuginfo" +#define ZEND_DEBUGINFO_FUNC_NAME "__debugInfo" +#define ZEND_DEBUGINFO_FUNC_LCNAME "__debuginfo" +#define ZEND_SLEEP_FUNC_NAME "__sleep" +#define ZEND_WAKEUP_FUNC_NAME "__wakeup" +#define ZEND_SERIALIZE_FUNC_NAME "__serialize" +#define ZEND_UNSERIALIZE_FUNC_NAME "__unserialize" +#define ZEND_SET_STATE_FUNC_NAME "__set_state" /* The following constants may be combined in CG(compiler_options) * to change the default compiler behavior */ diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index a5091f6c1b6f..7f0b58575387 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -92,21 +92,21 @@ static void zend_verify_enum_magic_methods(const zend_class_entry *ce) { // Only __get, __call, __debugInfo and __invoke are allowed - ZEND_ENUM_DISALLOW_MAGIC_METHOD(constructor, "__construct"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(destructor, "__destruct"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(clone, "__clone"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__get, "__get"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__set, "__set"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unset, "__unset"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__isset, "__isset"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__tostring, "__toString"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__serialize, "__serialize"); - ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unserialize, "__unserialize"); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(constructor, ZEND_CONSTRUCTOR_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(destructor, ZEND_DESTRUCTOR_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(clone, ZEND_CLONE_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__get, ZEND_GET_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__set, ZEND_SET_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unset, ZEND_UNSET_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__isset, ZEND_ISSET_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__tostring, ZEND_TOSTRING_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__serialize, ZEND_SERIALIZE_FUNC_NAME); + ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unserialize, ZEND_UNSERIALIZE_FUNC_NAME); static const char *const forbidden_methods[] = { - "__sleep", - "__wakeup", - "__set_state", + ZEND_SLEEP_FUNC_NAME, + ZEND_WAKEUP_FUNC_NAME, + ZEND_SET_STATE_FUNC_NAME, }; uint32_t forbidden_methods_length = sizeof(forbidden_methods) / sizeof(forbidden_methods[0]); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 0c6b22473514..538eff3ea34d 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -698,6 +698,10 @@ static void zend_extension_op_array_handler(zend_extension *extension, zend_op_a static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num) { for (uint32_t i = 0; i < op_array->last_try_catch; i++) { + if (!op_array->try_catch_array[i].finally_op) { + continue; + } + if ((op_num < op_array->try_catch_array[i].finally_op || op_num >= op_array->try_catch_array[i].finally_end) && (dst_num >= op_array->try_catch_array[i].finally_op && diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a43fdcc9a48b..ab8f2c2b54f8 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -3354,18 +3354,6 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1 } /* }}} */ -ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(const zval *s1, const zval *s2) /* {{{ */ -{ - return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2)); -} -/* }}} */ - -ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(const zval *s1, const zval *s2, const zval *s3) /* {{{ */ -{ - return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3)); -} -/* }}} */ - ZEND_API bool ZEND_FASTCALL zendi_smart_streq(const zend_string *s1, const zend_string *s2) /* {{{ */ { uint8_t ret1, ret2; diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 2dc6dbfbfc6d..27aa4fdb0486 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -46,7 +46,6 @@ #include "zend_portability.h" #include "zend_strtod.h" #include "zend_multiply.h" -#include "zend_object_handlers.h" #define LONG_SIGN_MASK ZEND_LONG_MIN @@ -487,8 +486,6 @@ static zend_always_inline zend_string* zend_string_toupper(zend_string *str) { return zend_string_toupper_ex(str, false); } -ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(const zval *s1, const zval *s2); -ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(const zval *s1, const zval *s2, const zval *s3); ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2); ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length); ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2); diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 3f0c9abd2596..930d733307f4 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -397,11 +397,22 @@ static zend_always_inline bool zend_string_equals(const zend_string *s1, const z return s1 == s2 || zend_string_equal_content(s1, s2); } -#define zend_string_equals_ci(s1, s2) \ - (ZSTR_LEN(s1) == ZSTR_LEN(s2) && !zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2))) +BEGIN_EXTERN_C() +ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2); +END_EXTERN_C() + +static zend_always_inline bool zend_string_equals_cstr_ci(const zend_string *s1, const char *s2, size_t s2_length) +{ + return ZSTR_LEN(s1) == s2_length && !zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), s2, s2_length); +} + +#define zend_string_equals_literal_ci(str, literal) \ + zend_string_equals_cstr_ci(str, "" literal, sizeof(literal) - 1) -#define zend_string_equals_literal_ci(str, c) \ - (ZSTR_LEN(str) == sizeof("" c) - 1 && !zend_binary_strcasecmp(ZSTR_VAL(str), ZSTR_LEN(str), (c), sizeof(c) - 1)) +static zend_always_inline bool zend_string_equals_ci(const zend_string *s1, const zend_string *s2) +{ + return zend_string_equals_cstr_ci(s1, ZSTR_VAL(s2), ZSTR_LEN(s2)); +} #define zend_string_equals_literal(str, literal) \ zend_string_equals_cstr(str, "" literal, sizeof(literal) - 1) diff --git a/Zend/zend_types.h b/Zend/zend_types.h index cfff3b942c4b..0edc4df37484 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -713,6 +713,116 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) { #define Z_TYPE_FLAGS_SHIFT 8 #define Z_TYPE_INFO_EXTRA_SHIFT 16 +/* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */ +#define GC_NOT_COLLECTABLE (1<<4) +#define GC_PROTECTED (1<<5) /* used for recursion detection */ +#define GC_IMMUTABLE (1<<6) /* can't be changed in place */ +#define GC_PERSISTENT (1<<7) /* allocated using malloc */ +#define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */ + +#define GC_TYPE_MASK 0x0000000f +#define GC_FLAGS_MASK 0x000003f0 +#define GC_INFO_MASK 0xfffffc00 +#define GC_FLAGS_SHIFT 0 +#define GC_INFO_SHIFT 10 + +static zend_always_inline uint8_t zval_gc_type(uint32_t gc_type_info) { + return (gc_type_info & GC_TYPE_MASK); +} + +static zend_always_inline uint32_t zval_gc_flags(uint32_t gc_type_info) { + return (gc_type_info >> GC_FLAGS_SHIFT) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT); +} + +static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { + return (gc_type_info >> GC_INFO_SHIFT); +} + +#define GC_TYPE_INFO(p) (p)->gc.u.type_info +#define GC_TYPE(p) zval_gc_type(GC_TYPE_INFO(p)) +#define GC_FLAGS(p) zval_gc_flags(GC_TYPE_INFO(p)) +#define GC_INFO(p) zval_gc_info(GC_TYPE_INFO(p)) + +#define GC_ADD_FLAGS(p, flags) do { \ + GC_TYPE_INFO(p) |= (flags) << GC_FLAGS_SHIFT; \ + } while (0) +#define GC_DEL_FLAGS(p, flags) do { \ + GC_TYPE_INFO(p) &= ~((flags) << GC_FLAGS_SHIFT); \ + } while (0) + +#ifndef ZEND_RC_DEBUG +# define ZEND_RC_DEBUG 0 +#endif + +#if ZEND_RC_DEBUG +extern ZEND_API bool zend_rc_debug; +/* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects. + * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ +# define ZEND_RC_MOD_CHECK(p) do { \ + if (zend_rc_debug) { \ + uint8_t type = zval_gc_type((p)->u.type_info); \ + if (type != IS_OBJECT && type != IS_NULL) { \ + ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ + ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ + } \ + } \ + } while (0) +# define GC_MAKE_PERSISTENT_LOCAL(p) do { \ + GC_ADD_FLAGS(p, GC_PERSISTENT_LOCAL); \ + } while (0) +#else +# define ZEND_RC_MOD_CHECK(p) \ + do { } while (0) +# define GC_MAKE_PERSISTENT_LOCAL(p) \ + do { } while (0) +#endif + +static zend_always_inline uint32_t zend_gc_refcount(const zend_refcounted_h *p) { + return p->refcount; +} + +static zend_always_inline uint32_t zend_gc_set_refcount(zend_refcounted_h *p, uint32_t rc) { + p->refcount = rc; + return p->refcount; +} + +static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) { + ZEND_RC_MOD_CHECK(p); + return ++(p->refcount); +} + +static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) { + if (!(p->u.type_info & GC_IMMUTABLE)) { + ZEND_RC_MOD_CHECK(p); + ++p->refcount; + } +} + +static zend_always_inline void zend_gc_try_delref(zend_refcounted_h *p) { + if (!(p->u.type_info & GC_IMMUTABLE)) { + ZEND_RC_MOD_CHECK(p); + --p->refcount; + } +} + +static zend_always_inline uint32_t zend_gc_delref(zend_refcounted_h *p) { + ZEND_ASSERT(p->refcount > 0); + ZEND_RC_MOD_CHECK(p); + return --(p->refcount); +} + +static zend_always_inline uint32_t zend_gc_addref_ex(zend_refcounted_h *p, uint32_t rc) { + ZEND_RC_MOD_CHECK(p); + p->refcount += rc; + return p->refcount; +} + +static zend_always_inline uint32_t zend_gc_delref_ex(zend_refcounted_h *p, uint32_t rc) { + ZEND_RC_MOD_CHECK(p); + p->refcount -= rc; + return p->refcount; +} + #define GC_REFCOUNT(p) zend_gc_refcount(&(p)->gc) #define GC_SET_REFCOUNT(p, rc) zend_gc_set_refcount(&(p)->gc, rc) #define GC_ADDREF(p) zend_gc_addref(&(p)->gc) @@ -754,54 +864,6 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) { } \ } while (0) -#define GC_TYPE_MASK 0x0000000f -#define GC_FLAGS_MASK 0x000003f0 -#define GC_INFO_MASK 0xfffffc00 -#define GC_FLAGS_SHIFT 0 -#define GC_INFO_SHIFT 10 - -static zend_always_inline uint8_t zval_gc_type(uint32_t gc_type_info) { - return (gc_type_info & GC_TYPE_MASK); -} - -static zend_always_inline uint32_t zval_gc_flags(uint32_t gc_type_info) { - return (gc_type_info >> GC_FLAGS_SHIFT) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT); -} - -static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { - return (gc_type_info >> GC_INFO_SHIFT); -} - -#define GC_TYPE_INFO(p) (p)->gc.u.type_info -#define GC_TYPE(p) zval_gc_type(GC_TYPE_INFO(p)) -#define GC_FLAGS(p) zval_gc_flags(GC_TYPE_INFO(p)) -#define GC_INFO(p) zval_gc_info(GC_TYPE_INFO(p)) - -#define GC_ADD_FLAGS(p, flags) do { \ - GC_TYPE_INFO(p) |= (flags) << GC_FLAGS_SHIFT; \ - } while (0) -#define GC_DEL_FLAGS(p, flags) do { \ - GC_TYPE_INFO(p) &= ~((flags) << GC_FLAGS_SHIFT); \ - } while (0) - -#define Z_GC_TYPE(zval) GC_TYPE(Z_COUNTED(zval)) -#define Z_GC_TYPE_P(zval_p) Z_GC_TYPE(*(zval_p)) - -#define Z_GC_FLAGS(zval) GC_FLAGS(Z_COUNTED(zval)) -#define Z_GC_FLAGS_P(zval_p) Z_GC_FLAGS(*(zval_p)) - -#define Z_GC_INFO(zval) GC_INFO(Z_COUNTED(zval)) -#define Z_GC_INFO_P(zval_p) Z_GC_INFO(*(zval_p)) -#define Z_GC_TYPE_INFO(zval) GC_TYPE_INFO(Z_COUNTED(zval)) -#define Z_GC_TYPE_INFO_P(zval_p) Z_GC_TYPE_INFO(*(zval_p)) - -/* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */ -#define GC_NOT_COLLECTABLE (1<<4) -#define GC_PROTECTED (1<<5) /* used for recursion detection */ -#define GC_IMMUTABLE (1<<6) /* can't be changed in place */ -#define GC_PERSISTENT (1<<7) /* allocated using malloc */ -#define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */ - #define GC_NULL (IS_NULL | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) #define GC_STRING (IS_STRING | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) #define GC_ARRAY IS_ARRAY @@ -1299,79 +1361,6 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define Z_TRY_ADDREF(z) Z_TRY_ADDREF_P(&(z)) #define Z_TRY_DELREF(z) Z_TRY_DELREF_P(&(z)) -#ifndef ZEND_RC_DEBUG -# define ZEND_RC_DEBUG 0 -#endif - -#if ZEND_RC_DEBUG -extern ZEND_API bool zend_rc_debug; -/* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects. - * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ -# define ZEND_RC_MOD_CHECK(p) do { \ - if (zend_rc_debug) { \ - uint8_t type = zval_gc_type((p)->u.type_info); \ - if (type != IS_OBJECT && type != IS_NULL) { \ - ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ - ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ - } \ - } \ - } while (0) -# define GC_MAKE_PERSISTENT_LOCAL(p) do { \ - GC_ADD_FLAGS(p, GC_PERSISTENT_LOCAL); \ - } while (0) -#else -# define ZEND_RC_MOD_CHECK(p) \ - do { } while (0) -# define GC_MAKE_PERSISTENT_LOCAL(p) \ - do { } while (0) -#endif - -static zend_always_inline uint32_t zend_gc_refcount(const zend_refcounted_h *p) { - return p->refcount; -} - -static zend_always_inline uint32_t zend_gc_set_refcount(zend_refcounted_h *p, uint32_t rc) { - p->refcount = rc; - return p->refcount; -} - -static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) { - ZEND_RC_MOD_CHECK(p); - return ++(p->refcount); -} - -static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) { - if (!(p->u.type_info & GC_IMMUTABLE)) { - ZEND_RC_MOD_CHECK(p); - ++p->refcount; - } -} - -static zend_always_inline void zend_gc_try_delref(zend_refcounted_h *p) { - if (!(p->u.type_info & GC_IMMUTABLE)) { - ZEND_RC_MOD_CHECK(p); - --p->refcount; - } -} - -static zend_always_inline uint32_t zend_gc_delref(zend_refcounted_h *p) { - ZEND_ASSERT(p->refcount > 0); - ZEND_RC_MOD_CHECK(p); - return --(p->refcount); -} - -static zend_always_inline uint32_t zend_gc_addref_ex(zend_refcounted_h *p, uint32_t rc) { - ZEND_RC_MOD_CHECK(p); - p->refcount += rc; - return p->refcount; -} - -static zend_always_inline uint32_t zend_gc_delref_ex(zend_refcounted_h *p, uint32_t rc) { - ZEND_RC_MOD_CHECK(p); - p->refcount -= rc; - return p->refcount; -} - static zend_always_inline uint32_t zval_refcount_p(const zval* pz) { #if ZEND_DEBUG ZEND_ASSERT(Z_REFCOUNTED_P(pz) || Z_TYPE_P(pz) == IS_ARRAY); diff --git a/ext/date/tests/gh-124.phpt b/ext/date/tests/gh-124.phpt index 074e519d4399..30cccd74ef1f 100644 --- a/ext/date/tests/gh-124.phpt +++ b/ext/date/tests/gh-124.phpt @@ -4,7 +4,7 @@ Test for timelib #124: Problem with large negative timestamps date.timezone=UTC --SKIPIF-- --FILE-- diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 1b8bd1f76784..a331cbd40cea 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -2318,13 +2318,13 @@ static void exif_iif_add_value(image_info_type *image_info, int section_index, c #ifdef EXIF_DEBUG php_error_docref(NULL, E_WARNING, "Found value of type single"); #endif - info_value->f = php_ifd_get_float(value); + info_value->f = php_ifd_get_float(vptr); break; case TAG_FMT_DOUBLE: #ifdef EXIF_DEBUG php_error_docref(NULL, E_WARNING, "Found value of type double"); #endif - info_value->d = php_ifd_get_double(value); + info_value->d = php_ifd_get_double(vptr); break; } } @@ -3750,7 +3750,7 @@ static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf, static void exif_process_APP1(image_info_type *ImageInfo, char *CharBuf, size_t length, size_t displacement) { /* Check the APP1 for Exif Identifier Code */ - static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + static const uchar ExifHeader[] = {'E', 'x', 'i', 'f', 0, 0}; if (length <= 8 || memcmp(CharBuf+2, ExifHeader, 6)) { exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Incorrect APP1 Exif Identifier Code"); return; @@ -4447,8 +4447,7 @@ static bool exif_scan_HEIF_header(image_info_type *ImageInfo, unsigned char *buf static bool exif_scan_WEBP_header(image_info_type *ImageInfo, size_t riff_size) { - /* "Exif\0\0" identifier code */ - static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + static const uchar ExifHeader[] = {'E', 'x', 'i', 'f', 0, 0}; unsigned char chunk_header[8]; size_t offset = 12; size_t riff_end = riff_size <= ImageInfo->FileSize - 8 ? riff_size + 8 : ImageInfo->FileSize; diff --git a/ext/ffi/tests/gh10403.phpt b/ext/ffi/tests/gh10403.phpt index 6bac0da92584..1c5c69113eef 100644 --- a/ext/ffi/tests/gh10403.phpt +++ b/ext/ffi/tests/gh10403.phpt @@ -3,7 +3,7 @@ GH-10403: Fix incorrect bitshifting and masking in ffi bitfield --EXTENSIONS-- ffi --SKIPIF-- - + --FILE-- --FILE-- load(...)); + var_dump(spl_autoload_unregister($this->load(...))); + spl_autoload_call('MissingDirect'); + + spl_autoload_register($this->missing(...)); + var_dump(spl_autoload_unregister($this->missing(...))); + spl_autoload_call('MissingTrampoline'); + + spl_autoload_register($this->load(...)); + var_dump(spl_autoload_unregister([$this, 'load'])); + spl_autoload_call('MissingArray'); + + spl_autoload_register($this(...)); + var_dump(spl_autoload_unregister($this)); + spl_autoload_call('MissingInvokable'); + } +} + +spl_autoload_register(autoload_string(...)); +var_dump(spl_autoload_unregister('autoload_string')); +spl_autoload_call('MissingString'); + +(new AutoloadTest())->run(); +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt b/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt index cf9a40062f84..f8a01f48a115 100644 --- a/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt +++ b/ext/standard/tests/GHSA-96wq-48vp-hh57.phpt @@ -8,7 +8,7 @@ memory_limit=3G --FILE-- getMessage(), PHP_EOL; +} + +try { + $f = new Foo(); + var_dump($f->{'---'}); + assert(!$f->{'---'}); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +string(3) "abc" +assert(!${'---'}) +string(3) "---" +assert(!$f->{'---'}) diff --git a/ext/standard/tests/general_functions/gh22118.phpt b/ext/standard/tests/general_functions/gh22118.phpt new file mode 100644 index 000000000000..32c1a0fa1dec --- /dev/null +++ b/ext/standard/tests/general_functions/gh22118.phpt @@ -0,0 +1,75 @@ +--TEST-- +GH-22118: unregister_tick_function() unregisters equivalent first-class method callables +--FILE-- +direct++; + } + + public function arrayCallable(): void + { + $this->array++; + } + + public function __invoke(): void + { + $this->invoke++; + } + + public function __call(string $name, array $arguments): void + { + $this->trampoline++; + } + + public function run(): void + { + register_tick_function($this->kick(...)); + unregister_tick_function($this->kick(...)); + echo "direct: {$this->direct}\n"; + + register_tick_function($this->missing(...)); + unregister_tick_function($this->missing(...)); + echo "trampoline: {$this->trampoline}\n"; + + register_tick_function($this->arrayCallable(...)); + unregister_tick_function([$this, 'arrayCallable']); + echo "array: {$this->array}\n"; + + register_tick_function($this(...)); + unregister_tick_function($this); + echo "invoke: {$this->invoke}\n"; + } +} + +register_tick_function(tick_string(...)); +unregister_tick_function('tick_string'); +echo "string: {$string}\n"; + +(new TickTest())->run(); +echo "done\n"; +?> +--EXPECT-- +string: 1 +direct: 1 +trampoline: 1 +array: 1 +invoke: 1 +done diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 0b1c8970f473..123f244a51d7 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -103,7 +103,7 @@ ZEND_ATTRIBUTE_NONNULL static UriUriA *get_normalized_uri(php_uri_parser_rfc3986 return &uriparser_uris->normalized_uri; } -ZEND_ATTRIBUTE_NONNULL static UriUriA *get_uri_for_reading(php_uri_parser_rfc3986_uris *uriparser_uris, php_uri_component_read_mode read_mode) +ZEND_ATTRIBUTE_NONNULL static UriUriA *get_uri_for_reading(php_uri_parser_rfc3986_uris *uriparser_uris, const php_uri_component_read_mode read_mode) { switch (read_mode) { case PHP_URI_COMPONENT_READ_MODE_RAW: @@ -140,7 +140,7 @@ ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_uri_type_read(php_uri_parser_ ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_type, type)); } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -177,7 +177,7 @@ static zend_result php_uri_parser_rfc3986_scheme_write(void *uri, const zval *va } } -ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_parser_rfc3986_uris *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_parser_rfc3986_uris *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -190,7 +190,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_ return SUCCESS; } -zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *uri, zval *value, zval *errors) +zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *uri, const zval *value, zval *errors) { UriUriA *uriparser_uri = get_uri_for_writing(uri); int result; @@ -217,7 +217,7 @@ zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *u } } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -239,7 +239,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(v return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_password_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_password_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -258,7 +258,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_password_read(v return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -335,7 +335,7 @@ static zend_result php_uri_parser_rfc3986_host_write(void *uri, const zval *valu } } -ZEND_ATTRIBUTE_NONNULL static zend_long port_str_to_zend_long_checked(const char *str, size_t len) +ZEND_ATTRIBUTE_NONNULL static zend_long port_str_to_zend_long_checked(const char *str, const size_t len) { if (len > MAX_LENGTH_OF_LONG) { return -1; @@ -353,7 +353,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_long port_str_to_zend_long_checked(const char return (zend_long)result; } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -395,7 +395,7 @@ static zend_result php_uri_parser_rfc3986_port_write(void *uri, const zval *valu } } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -463,7 +463,7 @@ static zend_result php_uri_parser_rfc3986_path_write(void *uri, const zval *valu } } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -500,7 +500,7 @@ static zend_result php_uri_parser_rfc3986_query_write(void *uri, const zval *val } } -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -619,7 +619,7 @@ php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str return NULL; } -void *php_uri_parser_rfc3986_parse(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) +static void *php_uri_parser_rfc3986_parse(const char *uri_str, const size_t uri_str_len, const void *base_url, zval *errors, bool silent) { return php_uri_parser_rfc3986_parse_ex(uri_str, uri_str_len, base_url, silent); } @@ -637,7 +637,7 @@ ZEND_ATTRIBUTE_NONNULL static void *php_uri_parser_rfc3986_clone(void *uri) return new_uriparser_uris; } -ZEND_ATTRIBUTE_NONNULL static zend_string *php_uri_parser_rfc3986_to_string(void *uri, php_uri_recomposition_mode recomposition_mode, bool exclude_fragment) +ZEND_ATTRIBUTE_NONNULL static zend_string *php_uri_parser_rfc3986_to_string(void *uri, const php_uri_recomposition_mode recomposition_mode, const bool exclude_fragment) { php_uri_parser_rfc3986_uris *uriparser_uris = uri; const UriUriA *uriparser_uri; diff --git a/ext/uri/uri_parser_rfc3986.h b/ext/uri/uri_parser_rfc3986.h index 633dd72062f2..a5fde7074323 100644 --- a/ext/uri/uri_parser_rfc3986.h +++ b/ext/uri/uri_parser_rfc3986.h @@ -25,7 +25,7 @@ ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_uri_type_read(php_uri_parser_ ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_host_type_read(php_uri_parser_rfc3986_uris *uri, zval *retval); zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_parser_rfc3986_uris *uri, php_uri_component_read_mode read_mode, zval *retval); -zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *uri, zval *value, zval *errors); +zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *uri, const zval *value, zval *errors); php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str, size_t uri_str_len, const php_uri_parser_rfc3986_uris *uriparser_base_url, bool silent); diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index 3ff1e1af166f..6d46feb51aae 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -43,9 +43,9 @@ static zend_always_inline void zval_string_or_null_to_lexbor_str(const zval *val static zend_always_inline void zval_long_or_null_to_lexbor_str(const zval *value, lexbor_str_t *lexbor_str) { if (Z_TYPE_P(value) == IS_LONG) { - zend_string *tmp = zend_long_to_str(Z_LVAL_P(value)); - lexbor_str_init_append(lexbor_str, lexbor_parser.mraw, (const lxb_char_t *) ZSTR_VAL(tmp), ZSTR_LEN(tmp)); - zend_string_release(tmp); + char buf[MAX_LENGTH_OF_LONG + 1]; + const char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, Z_LVAL_P(value)); + lexbor_str_init_append(lexbor_str, lexbor_parser.mraw, (const lxb_char_t *) res, strlen(res)); } else { ZEND_ASSERT(Z_ISNULL_P(value)); lexbor_str->data = (lxb_char_t *) ""; @@ -235,7 +235,7 @@ static void throw_invalid_url_exception_during_write(zval *errors, const char *c } } -static lxb_status_t serialize_to_smart_str_callback(const lxb_char_t *data, size_t length, void *ctx) +static lxb_status_t serialize_to_smart_str_callback(const lxb_char_t *data, const size_t length, void *ctx) { smart_str *uri_str = ctx; @@ -246,7 +246,7 @@ static lxb_status_t serialize_to_smart_str_callback(const lxb_char_t *data, size return LXB_STATUS_OK; } -static zend_result php_uri_parser_whatwg_scheme_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_scheme_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -348,7 +348,7 @@ static zend_result php_uri_parser_whatwg_password_write(void *uri, const zval *v return SUCCESS; } -static zend_result php_uri_parser_whatwg_host_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_host_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -435,7 +435,7 @@ static zend_result php_uri_parser_whatwg_host_write(void *uri, const zval *value return SUCCESS; } -static zend_result php_uri_parser_whatwg_port_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_port_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -466,7 +466,7 @@ static zend_result php_uri_parser_whatwg_port_write(void *uri, const zval *value return SUCCESS; } -static zend_result php_uri_parser_whatwg_path_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_path_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -497,7 +497,7 @@ static zend_result php_uri_parser_whatwg_path_write(void *uri, const zval *value return SUCCESS; } -static zend_result php_uri_parser_whatwg_query_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_query_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -528,7 +528,7 @@ static zend_result php_uri_parser_whatwg_query_write(void *uri, const zval *valu return SUCCESS; } -static zend_result php_uri_parser_whatwg_fragment_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_fragment_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -606,7 +606,7 @@ ZEND_MODULE_POST_ZEND_DEACTIVATE_D(uri_parser_whatwg) return SUCCESS; } -lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent) +lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, const size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, const bool silent) { lxb_url_parser_clean(&lexbor_parser); @@ -630,7 +630,7 @@ lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_le return url; } -static void *php_uri_parser_whatwg_parse(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) +static void *php_uri_parser_whatwg_parse(const char *uri_str, const size_t uri_str_len, const void *base_url, zval *errors, const bool silent) { return php_uri_parser_whatwg_parse_ex(uri_str, uri_str_len, base_url, errors, silent); } @@ -642,7 +642,7 @@ static void *php_uri_parser_whatwg_clone(void *uri) return lxb_url_clone(lexbor_parser.mraw, lexbor_uri); } -static zend_string *php_uri_parser_whatwg_to_string(void *uri, php_uri_recomposition_mode recomposition_mode, bool exclude_fragment) +static zend_string *php_uri_parser_whatwg_to_string(void *uri, const php_uri_recomposition_mode recomposition_mode, const bool exclude_fragment) { const lxb_url_t *lexbor_uri = uri; smart_str uri_str = {0};