diff --git a/.gitattributes b/.gitattributes index 8dea3f8bbafbd..74fd9f995e8da 100644 --- a/.gitattributes +++ b/.gitattributes @@ -21,6 +21,7 @@ # Collapse generated files within git and pull request diff. **/*_arginfo.h linguist-generated -diff +**/*_decl.h linguist-generated -diff /main/debug_gdb_scripts.c linguist-generated -diff /Zend/zend_vm_execute.h linguist-generated -diff /Zend/zend_vm_handlers.h linguist-generated -diff diff --git a/.github/actions/brew/action.yml b/.github/actions/brew/action.yml index 07595a5ada931..f90a66f239dee 100644 --- a/.github/actions/brew/action.yml +++ b/.github/actions/brew/action.yml @@ -13,11 +13,18 @@ runs: # Some packages exist on x86 but not arm, or vice versa. # Install them with reinstall to avoid warnings. - brew reinstall autoconf webp tidy-html5 libzip libsodium icu4c curl - brew install \ + brew reinstall -v \ + autoconf \ + webp \ + tidy-html5 \ + libzip \ + libsodium \ + icu4c \ + curl + brew install -v \ bison \ re2c - brew install \ + brew install -v \ bzip2 \ enchant \ libffi \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5c5af96c968de..423fe39bdc44c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -363,6 +363,7 @@ jobs: - name: Update clang uses: ./.github/actions/macos-update-clang - name: brew + timeout-minutes: 10 uses: ./.github/actions/brew - name: ./configure uses: ./.github/actions/configure-macos diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 64dc1ce6b60ed..ab917b518e1a6 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -242,6 +242,7 @@ jobs: - name: Update clang uses: ./.github/actions/macos-update-clang - name: brew + timeout-minutes: 10 uses: ./.github/actions/brew - name: ccache uses: hendrikmuhs/ccache-action@v1.2 diff --git a/NEWS b/NEWS index 7f3d46f7885dd..e26c9eca2fdb0 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,9 @@ PHP NEWS . Fixed GH-20564 (Don't call autoloaders with pending exception). (ilutov) . Fix deprecation now showing when accessing null key of an array with JIT. (alexandre-daubois) + . Fixed bug GH-20174 (Assertion failure in + ReflectionProperty::skipLazyInitialization after failed LazyProxy + initialization). (Arnaud) - Date: . Update timelib to 2022.16. (Derick) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index e35baa3df567f..9e2b3ae479407 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -60,11 +60,20 @@ PHP 8.6 INTERNALS UPGRADE NOTES automatically unwrap references when the result of the call is stored in an IS_TMP_VAR variable. This may be achieved by calling the zend_return_unwrap_ref() function. + . The php_math_round_mode_from_enum() function now takes a + zend_enum_RoundingMode parameter. + . Added Z_PARAM_ENUM(). + . Added zend_enum_fetch_case_id(). ======================== 2. Build system changes ======================== + . build/gen_stub.php may now generate a _decl.h file in addition to + the _arginfo.h file, if the stub declares enums and is annotated with + @generate-c-enums. For each enum the file will contain a C enum. Enum values + can be compared to the result of zend_enum_fetch_case_id(zend_object*). + ======================== 3. Module changes ======================== diff --git a/Zend/tests/lazy_objects/gh20174.phpt b/Zend/tests/lazy_objects/gh20174.phpt new file mode 100644 index 0000000000000..2bce09b4dc713 --- /dev/null +++ b/Zend/tests/lazy_objects/gh20174.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-20174: Assertion failure in ReflectionProperty::skipLazyInitialization after failed LazyProxy skipLazyInitialization +--CREDITS-- +vi3tL0u1s +--FILE-- +newLazyProxy(function ($obj) { + $obj->b = 4; + throw new Exception(); +}); + +try { + $reflector->initializeLazyObject($obj); +} catch (Exception $e) { + $reflector->getProperty('b')->skipLazyInitialization($obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +lazy proxy object(C)#%d (1) { + ["b"]=> + NULL +} diff --git a/Zend/tests/lazy_objects/gh20504-001.phpt b/Zend/tests/lazy_objects/gh20504-001.phpt new file mode 100644 index 0000000000000..c092e0f337fbc --- /dev/null +++ b/Zend/tests/lazy_objects/gh20504-001.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - isset +--CREDITS-- +vi3tL0u1s +--FILE-- +$name['']); + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +var_dump(isset($obj->name[''])); + +?> +--EXPECT-- +bool(false) diff --git a/Zend/tests/lazy_objects/gh20504-002.phpt b/Zend/tests/lazy_objects/gh20504-002.phpt new file mode 100644 index 0000000000000..c9cb7e743af6d --- /dev/null +++ b/Zend/tests/lazy_objects/gh20504-002.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - get +--FILE-- +$name; + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +var_dump($obj->name); + +?> +--EXPECTF-- +Warning: Undefined property: RealInstance::$name in %s on line %d +NULL diff --git a/Zend/tests/lazy_objects/gh20504-003.phpt b/Zend/tests/lazy_objects/gh20504-003.phpt new file mode 100644 index 0000000000000..df66e43a875ae --- /dev/null +++ b/Zend/tests/lazy_objects/gh20504-003.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - set +--FILE-- +$name = $value; + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +$obj->name = 0; + +var_dump($obj); + +?> +--EXPECTF-- +lazy proxy object(Proxy)#%d (1) { + ["instance"]=> + object(RealInstance)#%d (2) { + ["_"]=> + NULL + ["name"]=> + int(0) + } +} diff --git a/Zend/tests/lazy_objects/gh20504-004.phpt b/Zend/tests/lazy_objects/gh20504-004.phpt new file mode 100644 index 0000000000000..a80964a9ae98c --- /dev/null +++ b/Zend/tests/lazy_objects/gh20504-004.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - proxy defines __isset(), both have guards +--FILE-- +$name['']); + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +var_dump(isset($obj->name[''])); + +?> +--EXPECT-- +Proxy::__isset +Proxy::__get +bool(false) diff --git a/Zend/tests/lazy_objects/gh20504-005.phpt b/Zend/tests/lazy_objects/gh20504-005.phpt new file mode 100644 index 0000000000000..8a2519bde114b --- /dev/null +++ b/Zend/tests/lazy_objects/gh20504-005.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - unset +--FILE-- +$name); + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +unset($obj->name); + +var_dump($obj); + +?> +--EXPECTF-- +lazy proxy object(Proxy)#%d (1) { + ["instance"]=> + object(RealInstance)#%d (1) { + ["_"]=> + NULL + } +} diff --git a/Zend/tests/lazy_objects/gh20657-001.phpt b/Zend/tests/lazy_objects/gh20657-001.phpt new file mode 100644 index 0000000000000..ca3c70febca63 --- /dev/null +++ b/Zend/tests/lazy_objects/gh20657-001.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-20657: GC during zend_lazy_object_realize() +--CREDITS-- +vi3tL0u1s +--FILE-- +newLazyGhost(function ($obj) {}); + + // Add to roots + $obj2 = $obj; + unset($obj2); + + // Initialize all props to mark object non-lazy. Also create a cycle. + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["a"]=> + *RECURSION* +} diff --git a/Zend/tests/lazy_objects/gh20657-002.phpt b/Zend/tests/lazy_objects/gh20657-002.phpt new file mode 100644 index 0000000000000..daf9b767ba978 --- /dev/null +++ b/Zend/tests/lazy_objects/gh20657-002.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-20657 002: GC during zend_lazy_object_realize() - reset as lazy during realize() +--FILE-- +self = $this; + } + public function __destruct() { + global $obj, $reflector; + $reflector->resetAsLazyGhost($obj, function () {}); + } +} + +new D(); + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 10000; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) {}); + + // Add to roots + $obj2 = $obj; + unset($obj2); + + // Initialize all props to mark object non-lazy. Also create a cycle. + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["a"]=> + *RECURSION* +} diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt index 4edf9481ebc22..695da60229c75 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes.phpt @@ -46,7 +46,6 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the proxy are not reverted test('Proxy', $obj); --EXPECTF-- @@ -63,12 +62,10 @@ Is lazy: 1 # Proxy: string(11) "initializer" initializer exception -lazy proxy object(C)#%d (3) { - ["a"]=> - int(3) +lazy proxy object(C)#%d (1) { ["b"]=> - int(4) + uninitialized(int) ["c"]=> - int(5) + int(0) } Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt index ce94fc8b2ab79..19d3eac7a9f08 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props.phpt @@ -49,7 +49,6 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the proxy are not reverted test('Proxy', $obj); --EXPECTF-- @@ -66,14 +65,10 @@ Is lazy: 1 # Proxy: string(11) "initializer" initializer exception -lazy proxy object(C)#%d (4) { - ["a"]=> - int(3) +lazy proxy object(C)#%d (1) { ["b"]=> - int(4) + uninitialized(int) ["c"]=> - int(5) - ["d"]=> - int(6) + int(0) } Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt index 1bc3eb2cea8e1..c11a0eda7aaab 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_dyn_props_and_ht.phpt @@ -52,7 +52,6 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the proxy are not reverted test('Proxy', $obj); --EXPECTF-- @@ -73,14 +72,10 @@ array(0) { } string(11) "initializer" initializer exception -lazy proxy object(C)#%d (4) { - ["a"]=> - int(3) +lazy proxy object(C)#%d (1) { ["b"]=> - int(4) + uninitialized(int) ["c"]=> - int(5) - ["d"]=> - int(6) + int(0) } Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt index c4f0bd98773fd..7419a4a31da99 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht.phpt @@ -49,7 +49,6 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the proxy are not reverted test('Proxy', $obj); --EXPECTF-- @@ -74,12 +73,10 @@ array(1) { } string(11) "initializer" initializer exception -lazy proxy object(C)#%d (3) { - ["a"]=> - int(3) +lazy proxy object(C)#%d (1) { ["b"]=> - int(4) + uninitialized(int) ["c"]=> - int(5) + int(0) } Is lazy: 1 diff --git a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt index 094f5c9b80947..cea95c3c8a7b8 100644 --- a/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt +++ b/Zend/tests/lazy_objects/init_exception_reverts_initializer_changes_props_ht_ref.phpt @@ -55,7 +55,6 @@ $obj = $reflector->newLazyProxy(function ($obj) { throw new Exception('initializer exception'); }); -// Initializer effects on the proxy are not reverted test('Proxy', $obj); --EXPECTF-- @@ -83,13 +82,11 @@ array(1) { } string(11) "initializer" initializer exception -lazy proxy object(C)#%d (3) { - ["a"]=> - int(3) +lazy proxy object(C)#%d (1) { ["b"]=> - int(4) + uninitialized(int) ["c"]=> - int(5) + int(0) } Is lazy: 1 diff --git a/Zend/tests/oss-fuzz-481017027.phpt b/Zend/tests/oss-fuzz-481017027.phpt new file mode 100644 index 0000000000000..472133cfe845b --- /dev/null +++ b/Zend/tests/oss-fuzz-481017027.phpt @@ -0,0 +1,23 @@ +--TEST-- +OSS-Fuzz #481017027: Missing zend_fe_fetch_object_helper deref +--FILE-- +y = &$y; +test($obj, ''); + +?> +--EXPECT-- +int(42) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index c1ccbf13666a5..d78ee6604e34d 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -2009,6 +2009,13 @@ ZEND_API ZEND_COLD void zend_class_redeclaration_error_ex(int type, zend_string #define Z_PARAM_OBJ_OF_CLASS_OR_LONG_OR_NULL(dest_obj, _ce, dest_long, is_null) \ Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, is_null, 1) +#define Z_PARAM_ENUM(dest, _ce) \ + { \ + zend_object *_tmp = NULL; \ + Z_PARAM_OBJ_OF_CLASS(_tmp, _ce); \ + dest = zend_enum_fetch_case_id(_tmp); \ + } + /* old "p" */ #define Z_PARAM_PATH_EX(dest, dest_len, check_null, deref) \ Z_PARAM_PROLOGUE(deref, 0); \ diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 54bf4c0bf2e6d..a6071d2284130 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -995,10 +995,13 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( zend_ast *class_name_ast = ast->child[0]; zend_string *class_name = zend_ast_get_str(class_name_ast); - zend_ast *case_name_ast = ast->child[1]; + zend_ast *case_id_ast = ast->child[1]; + int case_id = (int)Z_LVAL_P(zend_ast_get_zval(case_id_ast)); + + zend_ast *case_name_ast = ast->child[2]; zend_string *case_name = zend_ast_get_str(case_name_ast); - zend_ast *case_value_ast = ast->child[2]; + zend_ast *case_value_ast = ast->child[3]; zval case_value_zv; ZVAL_UNDEF(&case_value_zv); @@ -1009,7 +1012,7 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( } zend_class_entry *ce = zend_lookup_class(class_name); - zend_enum_new(result, ce, case_name, case_value_ast != NULL ? &case_value_zv : NULL); + zend_enum_new(result, ce, case_id, case_name, case_value_ast != NULL ? &case_value_zv : NULL); zval_ptr_dtor_nogc(&case_value_zv); break; } diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index c212cd8367a87..a88efefd85b20 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -168,15 +168,15 @@ enum _zend_ast_kind { ZEND_AST_CONST_ELEM, ZEND_AST_CLASS_CONST_GROUP, - // Pseudo node for initializing enums - ZEND_AST_CONST_ENUM_INIT, - /* 4 child nodes */ ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_FOREACH, ZEND_AST_ENUM_CASE, ZEND_AST_PROP_ELEM, + // Pseudo node for initializing enums + ZEND_AST_CONST_ENUM_INIT, + /* 5 child nodes */ /* 6 child nodes */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2b2235e5df16b..688a50749a61d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -9756,6 +9756,11 @@ static void zend_compile_enum_case(zend_ast *ast) ZVAL_STR_COPY(&class_name_zval, enum_class_name); zend_ast *class_name_ast = zend_ast_create_zval(&class_name_zval); + zval case_id_zval; + int case_id = zend_enum_next_case_id(enum_class); + ZVAL_LONG(&case_id_zval, case_id); + zend_ast *case_id_ast = zend_ast_create_zval(&case_id_zval); + zval case_name_zval; ZVAL_STR_COPY(&case_name_zval, enum_case_name); zend_ast *case_name_ast = zend_ast_create_zval(&case_name_zval); @@ -9773,7 +9778,8 @@ static void zend_compile_enum_case(zend_ast *ast) ZSTR_VAL(enum_class_name)); } - zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, class_name_ast, case_name_ast, case_value_ast); + zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, + class_name_ast, case_id_ast, case_name_ast, case_value_ast); zval value_zv; zend_const_expr_to_zval(&value_zv, &const_enum_init_ast, /* allow_dynamic */ false); @@ -12669,7 +12675,7 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ zend_eval_const_expr(&ast->child[1]); return; case ZEND_AST_CONST_ENUM_INIT: - zend_eval_const_expr(&ast->child[2]); + zend_eval_const_expr(&ast->child[3]); return; case ZEND_AST_PROP: case ZEND_AST_NULLSAFE_PROP: diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index 7c62c8a96d0e3..6e9c68810d4b4 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -40,9 +40,16 @@ static zend_arg_info zarginfo_class_UnitEnum_cases[sizeof(arginfo_class_UnitEnum static zend_arg_info zarginfo_class_BackedEnum_from[sizeof(arginfo_class_BackedEnum_from)/sizeof(zend_internal_arg_info)]; static zend_arg_info zarginfo_class_BackedEnum_tryFrom[sizeof(arginfo_class_BackedEnum_tryFrom)/sizeof(zend_internal_arg_info)]; -zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case_name, zval *backing_value_zv) +zend_object *zend_enum_new(zval *result, zend_class_entry *ce, int case_id, zend_string *case_name, zval *backing_value_zv) { - zend_object *zobj = zend_objects_new(ce); + zend_enum_obj *intern = zend_object_alloc(sizeof(*intern), ce); + + zend_object_std_init(&intern->std, ce); + object_properties_init(&intern->std, ce); + + intern->case_id = case_id; + + zend_object *zobj = &intern->std; GC_ADD_FLAGS(zobj, GC_NOT_COLLECTABLE); ZVAL_OBJ(result, zobj); @@ -170,6 +177,7 @@ void zend_register_enum_ce(void) zend_ce_backed_enum->interface_gets_implemented = zend_implement_backed_enum; memcpy(&zend_enum_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + zend_enum_object_handlers.offset = XtOffsetOf(zend_enum_obj, std); zend_enum_object_handlers.clone_obj = NULL; zend_enum_object_handlers.compare = zend_objects_not_comparable; } @@ -539,16 +547,18 @@ ZEND_API zend_class_entry *zend_register_internal_enum( } static zend_ast_ref *create_enum_case_ast( - zend_string *class_name, zend_string *case_name, zval *value) { + zend_string *class_name, int case_id, zend_string *case_name, + zval *value) { // TODO: Use custom node type for enum cases? - size_t size = sizeof(zend_ast_ref) + zend_ast_size(3) - + (value ? 3 : 2) * sizeof(zend_ast_zval); + const size_t num_children = ZEND_AST_CONST_ENUM_INIT >> ZEND_AST_NUM_CHILDREN_SHIFT; + size_t size = sizeof(zend_ast_ref) + zend_ast_size(num_children) + + (value ? num_children : num_children-1) * sizeof(zend_ast_zval); char *p = pemalloc(size, 1); zend_ast_ref *ref = (zend_ast_ref *) p; p += sizeof(zend_ast_ref); GC_SET_REFCOUNT(ref, 1); GC_TYPE_INFO(ref) = GC_CONSTANT_AST | GC_PERSISTENT | GC_IMMUTABLE; - zend_ast *ast = (zend_ast *) p; p += zend_ast_size(3); + zend_ast *ast = (zend_ast *) p; p += zend_ast_size(num_children); ast->kind = ZEND_AST_CONST_ENUM_INIT; ast->attr = 0; ast->lineno = 0; @@ -563,24 +573,47 @@ static zend_ast_ref *create_enum_case_ast( ast->child[1] = (zend_ast *) p; p += sizeof(zend_ast_zval); ast->child[1]->kind = ZEND_AST_ZVAL; ast->child[1]->attr = 0; - ZEND_ASSERT(ZSTR_IS_INTERNED(case_name)); - ZVAL_STR(zend_ast_get_zval(ast->child[1]), case_name); + ZVAL_LONG(zend_ast_get_zval(ast->child[1]), case_id); Z_LINENO_P(zend_ast_get_zval(ast->child[1])) = 0; + ast->child[2] = (zend_ast *) p; p += sizeof(zend_ast_zval); + ast->child[2]->kind = ZEND_AST_ZVAL; + ast->child[2]->attr = 0; + ZEND_ASSERT(ZSTR_IS_INTERNED(case_name)); + ZVAL_STR(zend_ast_get_zval(ast->child[2]), case_name); + Z_LINENO_P(zend_ast_get_zval(ast->child[2])) = 0; + if (value) { - ast->child[2] = (zend_ast *) p; p += sizeof(zend_ast_zval); - ast->child[2]->kind = ZEND_AST_ZVAL; - ast->child[2]->attr = 0; + ast->child[3] = (zend_ast *) p; p += sizeof(zend_ast_zval); + ast->child[3]->kind = ZEND_AST_ZVAL; + ast->child[3]->attr = 0; ZEND_ASSERT(!Z_REFCOUNTED_P(value)); - ZVAL_COPY_VALUE(zend_ast_get_zval(ast->child[2]), value); - Z_LINENO_P(zend_ast_get_zval(ast->child[2])) = 0; + ZVAL_COPY_VALUE(zend_ast_get_zval(ast->child[3]), value); + Z_LINENO_P(zend_ast_get_zval(ast->child[3])) = 0; } else { - ast->child[2] = NULL; + ast->child[3] = NULL; } return ref; } +int zend_enum_next_case_id(zend_class_entry *enum_class) +{ + ZEND_HASH_REVERSE_FOREACH_VAL(&enum_class->constants_table, zval *zv) { + zend_class_constant *c = Z_PTR_P(zv); + if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) { + continue; + } + ZEND_ASSERT(Z_TYPE(c->value) == IS_CONSTANT_AST); + zend_ast *ast = Z_ASTVAL(c->value); + + ZEND_ASSERT(ast->kind == ZEND_AST_CONST_ENUM_INIT); + return Z_LVAL_P(zend_ast_get_zval(ast->child[1])) + 1; + } ZEND_HASH_FOREACH_END(); + + return 1; +} + ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, zval *value) { if (value) { @@ -602,9 +635,11 @@ ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, z ZEND_ASSERT(ce->enum_backing_type == IS_UNDEF); } + int case_id = zend_enum_next_case_id(ce); + zval ast_zv; Z_TYPE_INFO(ast_zv) = IS_CONSTANT_AST; - Z_AST(ast_zv) = create_enum_case_ast(ce->name, case_name, value); + Z_AST(ast_zv) = create_enum_case_ast(ce->name, case_id, case_name, value); zend_class_constant *c = zend_declare_class_constant_ex( ce, case_name, &ast_zv, ZEND_ACC_PUBLIC, NULL); ZEND_CLASS_CONST_FLAGS(c) |= ZEND_CLASS_CONST_IS_CASE; diff --git a/Zend/zend_enum.h b/Zend/zend_enum.h index 39743c73472c8..4d0799e4f0ac7 100644 --- a/Zend/zend_enum.h +++ b/Zend/zend_enum.h @@ -30,14 +30,25 @@ extern ZEND_API zend_class_entry *zend_ce_unit_enum; extern ZEND_API zend_class_entry *zend_ce_backed_enum; extern ZEND_API zend_object_handlers zend_enum_object_handlers; +typedef struct zend_enum_obj { + int case_id; + zend_object std; +} zend_enum_obj; + +static inline zend_enum_obj *zend_enum_obj_from_obj(zend_object *zobj) { + ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_ENUM); + return (zend_enum_obj*)((char*)(zobj) - XtOffsetOf(zend_enum_obj, std)); +} + void zend_enum_startup(void); void zend_register_enum_ce(void); void zend_enum_add_interfaces(zend_class_entry *ce); zend_result zend_enum_build_backed_enum_table(zend_class_entry *ce); -zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case_name, zval *backing_value_zv); +zend_object *zend_enum_new(zval *result, zend_class_entry *ce, int case_id, zend_string *case_name, zval *backing_value_zv); void zend_verify_enum(const zend_class_entry *ce); void zend_enum_register_funcs(zend_class_entry *ce); void zend_enum_register_props(zend_class_entry *ce); +int zend_enum_next_case_id(zend_class_entry *enum_class); ZEND_API zend_class_entry *zend_register_internal_enum( const char *name, uint8_t type, const zend_function_entry *functions); @@ -47,6 +58,12 @@ ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char *name); ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try_from); +static zend_always_inline int zend_enum_fetch_case_id(zend_object *zobj) +{ + ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_ENUM); + return zend_enum_obj_from_obj(zobj)->case_id; +} + static zend_always_inline zval *zend_enum_fetch_case_name(zend_object *zobj) { ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_ENUM); diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index a0cb1dfcdff19..e88ecf9fbe657 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -479,6 +479,24 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) /* prevent reentrant initialization */ OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY); + zval *properties_table_snapshot = NULL; + + /* Snapshot dynamic properties */ + HashTable *properties_snapshot = obj->properties; + if (properties_snapshot) { + GC_TRY_ADDREF(properties_snapshot); + } + + /* Snapshot declared properties */ + if (obj->ce->default_properties_count) { + zval *properties_table = obj->properties_table; + properties_table_snapshot = emalloc(sizeof(*properties_table_snapshot) * obj->ce->default_properties_count); + + for (int i = 0; i < obj->ce->default_properties_count; i++) { + ZVAL_COPY_PROP(&properties_table_snapshot[i], &properties_table[i]); + } + } + /* Call factory */ zval retval; int argc = 1; @@ -492,33 +510,29 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) zend_call_known_fcc(initializer, &retval, argc, &zobj, named_params); if (UNEXPECTED(EG(exception))) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; - goto exit; + goto fail; } if (UNEXPECTED(Z_TYPE(retval) != IS_OBJECT)) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_type_error("Lazy proxy factory must return an instance of a class compatible with %s, %s returned", ZSTR_VAL(obj->ce->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); - goto exit; + goto fail; } if (UNEXPECTED(Z_TYPE(retval) != IS_OBJECT || !zend_lazy_object_compatible(Z_OBJ(retval), obj))) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_type_error("The real instance class %s is not compatible with the proxy class %s. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods.", zend_zval_value_name(&retval), ZSTR_VAL(obj->ce->name)); zval_ptr_dtor(&retval); - goto exit; + goto fail; } if (UNEXPECTED(Z_OBJ(retval) == obj || zend_object_is_lazy(Z_OBJ(retval)))) { - OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object"); zval_ptr_dtor(&retval); - goto exit; + goto fail; } zend_fcc_dtor(&info->u.initializer.fcc); @@ -542,6 +556,21 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) } } + if (properties_table_snapshot) { + for (int i = 0; i < obj->ce->default_properties_count; i++) { + zval *p = &properties_table_snapshot[i]; + /* Use zval_ptr_dtor directly here (not zend_object_dtor_property), + * as any reference type_source will have already been deleted in + * case the prop is not bound to this value anymore. */ + i_zval_ptr_dtor(p); + } + efree(properties_table_snapshot); + } + + if (properties_snapshot) { + zend_release_properties(properties_snapshot); + } + instance = Z_OBJ(retval); exit: @@ -554,6 +583,11 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj) } return instance; + +fail: + OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY; + zend_lazy_object_revert_init(obj, properties_table_snapshot, properties_snapshot); + goto exit; } /* Initialize a lazy object. */ @@ -678,8 +712,6 @@ void zend_lazy_object_realize(zend_object *obj) ZEND_ASSERT(zend_object_is_lazy(obj)); ZEND_ASSERT(!zend_lazy_object_initialized(obj)); - zend_lazy_object_del_info(obj); - #if ZEND_DEBUG for (int i = 0; i < obj->ce->default_properties_count; i++) { ZEND_ASSERT(!(Z_PROP_FLAG_P(&obj->properties_table[i]) & IS_PROP_LAZY)); @@ -687,6 +719,7 @@ void zend_lazy_object_realize(zend_object *obj) #endif OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED | IS_OBJ_LAZY_PROXY); + zend_lazy_object_del_info(obj); } ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index d1da6de5191f7..45eac02949d15 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -962,25 +962,27 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int uninit_error: if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { if (!prop_info || (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY)) { - zobj = zend_lazy_object_init(zobj); - if (!zobj) { + zend_object *instance = zend_lazy_object_init(zobj); + if (!instance) { retval = &EG(uninitialized_zval); goto exit; } - if (UNEXPECTED(guard)) { + if (UNEXPECTED(guard && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS))) { + /* Find which guard was used on zobj, so we can set the same + * guard on instance. */ uint32_t guard_type = (type == BP_VAR_IS) && zobj->ce->__isset ? IN_ISSET : IN_GET; - guard = zend_get_property_guard(zobj, name); + guard = zend_get_property_guard(instance, name); if (!((*guard) & guard_type)) { (*guard) |= guard_type; - retval = zend_std_read_property(zobj, name, type, cache_slot, rv); + retval = zend_std_read_property(instance, name, type, cache_slot, rv); (*guard) &= ~guard_type; return retval; } } - return zend_std_read_property(zobj, name, type, cache_slot, rv); + return zend_std_read_property(instance, name, type, cache_slot, rv); } } if (type != BP_VAR_IS) { @@ -1019,7 +1021,7 @@ static zval *forward_write_to_lazy_object(zend_object *zobj, return &EG(error_zval); } - if (UNEXPECTED(guarded)) { + if (UNEXPECTED(guarded && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS))) { uint32_t *guard = zend_get_property_guard(instance, name); if (!((*guard) & IN_SET)) { (*guard) |= IN_SET; @@ -1605,7 +1607,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void return; } - if (UNEXPECTED(guard)) { + if (UNEXPECTED(guard && zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS)) { guard = zend_get_property_guard(zobj, name); if (!((*guard) & IN_UNSET)) { (*guard) |= IN_UNSET; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7723650cb1c2c..6551ce23e27c1 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -7183,6 +7183,10 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): zval *variable_ptr = EX_VAR(opline->op2.var); zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } else { + if (UNEXPECTED(Z_ISREF_P(value))) { + value = Z_REFVAL_P(value); + value_type = Z_TYPE_INFO_P(value); + } zval *res = EX_VAR(opline->op2.var); zend_refcounted *gc = Z_COUNTED_P(value); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4745b2a2652bd..07588c0e76937 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3106,6 +3106,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zval *variable_ptr = EX_VAR(opline->op2.var); zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } else { + if (UNEXPECTED(Z_ISREF_P(value))) { + value = Z_REFVAL_P(value); + value_type = Z_TYPE_INFO_P(value); + } zval *res = EX_VAR(opline->op2.var); zend_refcounted *gc = Z_COUNTED_P(value); @@ -55764,6 +55768,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend zval *variable_ptr = EX_VAR(opline->op2.var); zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } else { + if (UNEXPECTED(Z_ISREF_P(value))) { + value = Z_REFVAL_P(value); + value_type = Z_TYPE_INFO_P(value); + } zval *res = EX_VAR(opline->op2.var); zend_refcounted *gc = Z_COUNTED_P(value); diff --git a/build/gen_stub.php b/build/gen_stub.php index 2670e85458dba..64273e24bd838 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -82,11 +82,22 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly = $stubFilenameWithoutExtension = str_replace(".stub.php", "", $stubFile); $arginfoFile = "{$stubFilenameWithoutExtension}_arginfo.h"; $legacyFile = "{$stubFilenameWithoutExtension}_legacy_arginfo.h"; - + $declFile = "{$stubFilenameWithoutExtension}_decl.h"; + + /* Check if the stub file changed, by checking that the hash stored + * in the generated arginfo.h matches. + * Also check that the decl.h file has the same hash. At this point + * we don't know if a decl.h file is supposed to exist, so extract + * this information (whether a decl file should exist) from the + * arginfo.h file. */ $stubCode = file_get_contents($stubFile); $stubHash = sha1(str_replace("\r\n", "\n", $stubCode)); $oldStubHash = extractStubHash($arginfoFile); - if ($stubHash === $oldStubHash && !$context->forceParse) { + $hasDeclHeader = extractHasDeclHeader($arginfoFile); + $oldStubHashDecl = extractStubHash($declFile); + $generatedFilesUpToDate = $stubHash === $oldStubHash + && ($hasDeclHeader ? $stubHash === $oldStubHashDecl : $oldStubHashDecl === null); + if ($generatedFilesUpToDate && !$context->forceParse) { /* Stub file did not change, do not regenerate. */ return null; } @@ -122,26 +133,31 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly = return $fileInfo; } - $arginfoCode = generateArgInfoCode( + [$arginfoCode, $declCode] = generateArgInfoCode( basename($stubFilenameWithoutExtension), $fileInfo, $context->allConstInfos, $stubHash ); - if ($context->forceRegeneration || $stubHash !== $oldStubHash) { + if ($context->forceRegeneration || !$generatedFilesUpToDate) { reportFilePutContents($arginfoFile, $arginfoCode); + if ($declCode !== '') { + reportFilePutContents($declFile, $declCode); + } else if (file_exists($declFile)) { + unlink($declFile); + } } if ($fileInfo->shouldGenerateLegacyArginfo()) { $legacyFileInfo = $fileInfo->getLegacyVersion(); - $arginfoCode = generateArgInfoCode( + [$arginfoCode] = generateArgInfoCode( basename($stubFilenameWithoutExtension), $legacyFileInfo, $context->allConstInfos, $stubHash ); - if ($context->forceRegeneration || $stubHash !== $oldStubHash) { + if ($context->forceRegeneration || !$generatedFilesUpToDate) { reportFilePutContents($legacyFile, $arginfoCode); } } @@ -159,13 +175,22 @@ function extractStubHash(string $arginfoFile): ?string { } $arginfoCode = file_get_contents($arginfoFile); - if (!preg_match('/\* Stub hash: ([0-9a-f]+) \*/', $arginfoCode, $matches)) { + if (!preg_match('/\* Stub hash: ([0-9a-f]+)/', $arginfoCode, $matches)) { return null; } return $matches[1]; } +function extractHasDeclHeader(string $arginfoFile): bool { + if (!file_exists($arginfoFile)) { + return false; + } + + $arginfoCode = file_get_contents($arginfoFile); + return str_contains($arginfoCode, '* Has decl header: yes *'); +} + class Context { public bool $forceParse = false; public bool $forceRegeneration = false; @@ -3278,7 +3303,7 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie } class EnumCaseInfo { - private /* readonly */ string $name; + public /* readonly */ string $name; private /* readonly */ ?Expr $value; public function __construct(string $name, ?Expr $value) { @@ -3661,6 +3686,38 @@ function (Name $item) { return $code; } + public function getCDeclarations(): string + { + if ($this->type !== "enum") { + return ''; + } + + $code = ''; + + if ($this->cond) { + $code .= "#if {$this->cond}\n"; + } + + $cEnumName = 'zend_enum_' . str_replace('\\', '_', $this->name->toString()); + + $code .= "typedef enum {$cEnumName} {\n"; + + $i = 1; + foreach ($this->enumCaseInfos as $case) { + $cName = 'ZEND_ENUM_' . str_replace('\\', '_', $this->name->toString()) . '_' . $case->name; + $code .= "\t{$cName} = {$i},\n"; + $i++; + } + + $code .= "} {$cEnumName};\n"; + + if ($this->cond) { + $code .= "#endif\n"; + } + + return $code; + } + private function getFlagsByPhpVersion(): VersionFlags { $php70Flags = []; @@ -4192,6 +4249,7 @@ class FileInfo { public bool $generateFunctionEntries = false; public string $declarationPrefix = ""; public bool $generateClassEntries = false; + public bool $generateCEnums = false; private bool $isUndocumentable = false; private bool $legacyArginfoGeneration = false; private ?int $minimumPhpVersionIdCompatibility = null; @@ -4217,6 +4275,8 @@ public function __construct(array $fileTags) { $this->declarationPrefix = $tag->value ? $tag->value . " " : ""; } else if ($tag->name === 'undocumentable') { $this->isUndocumentable = true; + } else if ($tag->name === 'generate-c-enums') { + $this->generateCEnums = true; } } @@ -4515,6 +4575,23 @@ public function generateClassEntryCode(array $allConstInfos): string { return $code; } + + public function generateCDeclarations(): string { + $code = ""; + + if (!$this->generateCEnums) { + return $code; + } + + foreach ($this->classInfos as $class) { + $cdecl = $class->getCDeclarations(); + if ($cdecl !== '') { + $code .= "\n" . $cdecl; + } + } + + return $code; + } } class DocCommentTag { @@ -5150,15 +5227,15 @@ function generateCodeWithConditions( /** * @param array $allConstInfos + * @return array{string, string} */ function generateArgInfoCode( string $stubFilenameWithoutExtension, FileInfo $fileInfo, array $allConstInfos, string $stubHash -): string { - $code = "/* This is a generated file, edit {$stubFilenameWithoutExtension}.stub.php instead.\n" - . " * Stub hash: $stubHash */\n"; +): array { + $code = ""; $generatedFuncInfos = []; @@ -5250,7 +5327,26 @@ static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarat $code .= $fileInfo->generateClassEntryCode($allConstInfos); } - return $code; + $hasDeclFile = false; + $declCode = $fileInfo->generateCDeclarations(); + if ($declCode !== '') { + $hasDeclFile = true; + $headerName = "ZEND_" . strtoupper($stubFilenameWithoutExtension) . "_DECL_{$stubHash}_H"; + $declCode = "/* This is a generated file, edit {$stubFilenameWithoutExtension}.stub.php instead.\n" + . " * Stub hash: $stubHash */\n" + . "\n" + . "#ifndef {$headerName}\n" + . "#define {$headerName}\n" + . $declCode . "\n" + . "#endif /* {$headerName} */\n"; + } + + $code = "/* This is a generated file, edit {$stubFilenameWithoutExtension}.stub.php instead.\n" + . " * Stub hash: $stubHash" + . ($hasDeclFile ? "\n * Has decl header: yes */\n" : " */\n") + . $code; + + return [$code, $declCode]; } /** @param FuncInfo[] $funcInfos */ diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index df2b96e68a715..539fa9d9cf5e2 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -25,6 +25,7 @@ #include "php_ini.h" #include "zend_exceptions.h" #include "zend_interfaces.h" +#include "zend_enum.h" #include "bcmath_arginfo.h" #include "ext/standard/info.h" #include "php_bcmath.h" @@ -787,30 +788,25 @@ PHP_FUNCTION(bcround) { zend_string *numstr; zend_long precision = 0; - zend_long mode = PHP_ROUND_HALF_UP; - zend_object *mode_object = NULL; + zend_enum_RoundingMode rounding_mode = ZEND_ENUM_RoundingMode_HalfAwayFromZero; bc_num num = NULL, result; ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STR(numstr) Z_PARAM_OPTIONAL Z_PARAM_LONG(precision) - Z_PARAM_OBJ_OF_CLASS(mode_object, rounding_mode_ce) + Z_PARAM_ENUM(rounding_mode, rounding_mode_ce) ZEND_PARSE_PARAMETERS_END(); - if (mode_object != NULL) { - mode = php_math_round_mode_from_enum(mode_object); - } - - switch (mode) { - case PHP_ROUND_HALF_UP: - case PHP_ROUND_HALF_DOWN: - case PHP_ROUND_HALF_EVEN: - case PHP_ROUND_HALF_ODD: - case PHP_ROUND_CEILING: - case PHP_ROUND_FLOOR: - case PHP_ROUND_TOWARD_ZERO: - case PHP_ROUND_AWAY_FROM_ZERO: + switch (rounding_mode) { + case ZEND_ENUM_RoundingMode_HalfAwayFromZero: + case ZEND_ENUM_RoundingMode_HalfTowardsZero: + case ZEND_ENUM_RoundingMode_HalfEven: + case ZEND_ENUM_RoundingMode_HalfOdd: + case ZEND_ENUM_RoundingMode_TowardsZero: + case ZEND_ENUM_RoundingMode_AwayFromZero: + case ZEND_ENUM_RoundingMode_NegativeInfinity: + case ZEND_ENUM_RoundingMode_PositiveInfinity: break; default: /* This is currently unreachable, but might become reachable when new modes are added. */ @@ -827,7 +823,7 @@ PHP_FUNCTION(bcround) goto cleanup; } - size_t scale = bc_round(num, precision, mode, &result); + size_t scale = bc_round(num, precision, rounding_mode, &result); RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { @@ -1796,30 +1792,26 @@ PHP_METHOD(BcMath_Number, ceil) PHP_METHOD(BcMath_Number, round) { zend_long precision = 0; - zend_long rounding_mode = PHP_ROUND_HALF_UP; - zend_object *mode_object = NULL; + zend_enum_RoundingMode rounding_mode = ZEND_ENUM_RoundingMode_HalfAwayFromZero; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_LONG(precision); - Z_PARAM_OBJ_OF_CLASS(mode_object, rounding_mode_ce); + Z_PARAM_ENUM(rounding_mode, rounding_mode_ce); ZEND_PARSE_PARAMETERS_END(); - if (mode_object != NULL) { - rounding_mode = php_math_round_mode_from_enum(mode_object); - } - switch (rounding_mode) { - case PHP_ROUND_HALF_UP: - case PHP_ROUND_HALF_DOWN: - case PHP_ROUND_HALF_EVEN: - case PHP_ROUND_HALF_ODD: - case PHP_ROUND_CEILING: - case PHP_ROUND_FLOOR: - case PHP_ROUND_TOWARD_ZERO: - case PHP_ROUND_AWAY_FROM_ZERO: + case ZEND_ENUM_RoundingMode_HalfAwayFromZero: + case ZEND_ENUM_RoundingMode_HalfTowardsZero: + case ZEND_ENUM_RoundingMode_HalfEven: + case ZEND_ENUM_RoundingMode_HalfOdd: + case ZEND_ENUM_RoundingMode_TowardsZero: + case ZEND_ENUM_RoundingMode_AwayFromZero: + case ZEND_ENUM_RoundingMode_NegativeInfinity: + case ZEND_ENUM_RoundingMode_PositiveInfinity: break; default: + /* This is currently unreachable, but might become reachable when new modes are added. */ zend_argument_value_error(2, "is an unsupported rounding mode"); RETURN_THROWS(); } diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index fa335ae404808..970286b8a261e 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -155,7 +155,7 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale) bc_num bc_floor_or_ceil(bc_num num, bool is_floor); -size_t bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result); +size_t bc_round(bc_num num, zend_long places, zend_enum_RoundingMode mode, bc_num *result); typedef enum { BC_RAISE_STATUS_OK, diff --git a/ext/bcmath/libbcmath/src/round.c b/ext/bcmath/libbcmath/src/round.c index 44df6036cbe3b..ec0042a9f4826 100644 --- a/ext/bcmath/libbcmath/src/round.c +++ b/ext/bcmath/libbcmath/src/round.c @@ -19,7 +19,7 @@ #include /* Returns the scale of the value after rounding. */ -size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) +size_t bc_round(bc_num num, zend_long precision, zend_enum_RoundingMode mode, bc_num *result) { /* clear result */ bc_free_num(result); @@ -38,32 +38,30 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) /* e.g. value is 0.1 and precision is -3, ret is 0 or 1000 */ if (precision < 0 && num->n_len < (size_t) (-(precision + Z_L(1))) + 1) { switch (mode) { - case PHP_ROUND_HALF_UP: - case PHP_ROUND_HALF_DOWN: - case PHP_ROUND_HALF_EVEN: - case PHP_ROUND_HALF_ODD: - case PHP_ROUND_TOWARD_ZERO: + case ZEND_ENUM_RoundingMode_HalfAwayFromZero: + case ZEND_ENUM_RoundingMode_HalfTowardsZero: + case ZEND_ENUM_RoundingMode_HalfEven: + case ZEND_ENUM_RoundingMode_HalfOdd: + case ZEND_ENUM_RoundingMode_TowardsZero: *result = bc_copy_num(BCG(_zero_)); return 0; - case PHP_ROUND_CEILING: + case ZEND_ENUM_RoundingMode_PositiveInfinity: if (num->n_sign == MINUS) { *result = bc_copy_num(BCG(_zero_)); return 0; } break; - case PHP_ROUND_FLOOR: + case ZEND_ENUM_RoundingMode_NegativeInfinity: if (num->n_sign == PLUS) { *result = bc_copy_num(BCG(_zero_)); return 0; } break; - case PHP_ROUND_AWAY_FROM_ZERO: + case ZEND_ENUM_RoundingMode_AwayFromZero: break; - - EMPTY_SWITCH_DEFAULT_CASE() } if (bc_is_zero(num)) { @@ -117,7 +115,7 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) /* Check cases that can be determined without looping. */ switch (mode) { - case PHP_ROUND_HALF_UP: + case ZEND_ENUM_RoundingMode_HalfAwayFromZero: if (*nptr >= 5) { goto up; } else if (*nptr < 5) { @@ -125,9 +123,9 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) } break; - case PHP_ROUND_HALF_DOWN: - case PHP_ROUND_HALF_EVEN: - case PHP_ROUND_HALF_ODD: + case ZEND_ENUM_RoundingMode_HalfTowardsZero: + case ZEND_ENUM_RoundingMode_HalfEven: + case ZEND_ENUM_RoundingMode_HalfOdd: if (*nptr > 5) { goto up; } else if (*nptr < 5) { @@ -136,7 +134,7 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) /* if *nptr == 5, we need to look-up further digits before making a decision. */ break; - case PHP_ROUND_CEILING: + case ZEND_ENUM_RoundingMode_PositiveInfinity: if (num->n_sign != PLUS) { goto check_zero; } else if (*nptr > 0) { @@ -145,7 +143,7 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) /* if *nptr == 0, a loop is required for judgment. */ break; - case PHP_ROUND_FLOOR: + case ZEND_ENUM_RoundingMode_NegativeInfinity: if (num->n_sign != MINUS) { goto check_zero; } else if (*nptr > 0) { @@ -154,17 +152,15 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) /* if *nptr == 0, a loop is required for judgment. */ break; - case PHP_ROUND_TOWARD_ZERO: + case ZEND_ENUM_RoundingMode_TowardsZero: goto check_zero; - case PHP_ROUND_AWAY_FROM_ZERO: + case ZEND_ENUM_RoundingMode_AwayFromZero: if (*nptr > 0) { goto up; } /* if *nptr == 0, a loop is required for judgment. */ break; - - EMPTY_SWITCH_DEFAULT_CASE() } /* Loop through the remaining digits. */ @@ -180,19 +176,19 @@ size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) } switch (mode) { - case PHP_ROUND_HALF_DOWN: - case PHP_ROUND_CEILING: - case PHP_ROUND_FLOOR: - case PHP_ROUND_AWAY_FROM_ZERO: + case ZEND_ENUM_RoundingMode_HalfTowardsZero: + case ZEND_ENUM_RoundingMode_PositiveInfinity: + case ZEND_ENUM_RoundingMode_NegativeInfinity: + case ZEND_ENUM_RoundingMode_AwayFromZero: goto check_zero; - case PHP_ROUND_HALF_EVEN: + case ZEND_ENUM_RoundingMode_HalfEven: if (rounded_len == 0 || num->n_value[rounded_len - 1] % 2 == 0) { goto check_zero; } break; - case PHP_ROUND_HALF_ODD: + case ZEND_ENUM_RoundingMode_HalfOdd: if (rounded_len != 0 && num->n_value[rounded_len - 1] % 2 == 1) { goto check_zero; } diff --git a/ext/bcmath/php_bcmath.h b/ext/bcmath/php_bcmath.h index 6b6098a23945e..83894fd7ca6b0 100644 --- a/ext/bcmath/php_bcmath.h +++ b/ext/bcmath/php_bcmath.h @@ -17,9 +17,9 @@ #ifndef PHP_BCMATH_H #define PHP_BCMATH_H +#include "ext/standard/php_math_round_mode.h" #include "libbcmath/src/bcmath.h" #include "zend_API.h" -#include "ext/standard/php_math_round_mode.h" extern zend_module_entry bcmath_module_entry; #define phpext_bcmath_ptr &bcmath_module_entry diff --git a/ext/dom/element.c b/ext/dom/element.c index 797f215e173d1..25bd306bcd808 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -1601,9 +1601,10 @@ PHP_METHOD(DOMElement, replaceChildren) #define INSERT_ADJACENT_RES_SYNTAX_FAILED INSERT_ADJACENT_RES_ADOPT_FAILED #define INSERT_ADJACENT_RES_PRE_INSERT_FAILED ((void*) -2) -static xmlNodePtr dom_insert_adjacent(const zend_string *where, xmlNodePtr thisp, dom_object *this_intern, xmlNodePtr otherp) +static xmlNodePtr dom_insert_adjacent(zend_enum_Dom_AdjacentPosition where, xmlNodePtr thisp, dom_object *this_intern, xmlNodePtr otherp) { - if (zend_string_equals_literal_ci(where, "beforebegin")) { + switch (where) { + case ZEND_ENUM_Dom_AdjacentPosition_BeforeBegin: if (thisp->parent == NULL) { return NULL; } @@ -1613,21 +1614,24 @@ static xmlNodePtr dom_insert_adjacent(const zend_string *where, xmlNodePtr thisp if (!php_dom_pre_insert(this_intern->document, otherp, thisp->parent, thisp)) { return INSERT_ADJACENT_RES_PRE_INSERT_FAILED; } - } else if (zend_string_equals_literal_ci(where, "afterbegin")) { + break; + case ZEND_ENUM_Dom_AdjacentPosition_AfterBegin: if (!php_dom_adopt_node(otherp, this_intern, thisp->doc)) { return INSERT_ADJACENT_RES_ADOPT_FAILED; } if (!php_dom_pre_insert(this_intern->document, otherp, thisp, thisp->children)) { return INSERT_ADJACENT_RES_PRE_INSERT_FAILED; } - } else if (zend_string_equals_literal_ci(where, "beforeend")) { + break; + case ZEND_ENUM_Dom_AdjacentPosition_BeforeEnd: if (!php_dom_adopt_node(otherp, this_intern, thisp->doc)) { return INSERT_ADJACENT_RES_ADOPT_FAILED; } if (!php_dom_pre_insert(this_intern->document, otherp, thisp, NULL)) { return INSERT_ADJACENT_RES_PRE_INSERT_FAILED; } - } else if (zend_string_equals_literal_ci(where, "afterend")) { + break; + case ZEND_ENUM_Dom_AdjacentPosition_AfterEnd: if (thisp->parent == NULL) { return NULL; } @@ -1637,9 +1641,7 @@ static xmlNodePtr dom_insert_adjacent(const zend_string *where, xmlNodePtr thisp if (!php_dom_pre_insert(this_intern->document, otherp, thisp->parent, thisp->next)) { return INSERT_ADJACENT_RES_PRE_INSERT_FAILED; } - } else { - php_dom_throw_error(SYNTAX_ERR, dom_get_strict_error(this_intern->document)); - return INSERT_ADJACENT_RES_SYNTAX_FAILED; + break; } return otherp; } @@ -1647,7 +1649,7 @@ static xmlNodePtr dom_insert_adjacent(const zend_string *where, xmlNodePtr thisp /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacentelement Since: */ -static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, const zend_string *where, zval *element_zval) +static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, zend_enum_Dom_AdjacentPosition where, zval *element_zval) { zval *id; xmlNodePtr thisp, otherp; @@ -1666,12 +1668,41 @@ static void dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAMETERS, co } } +static zend_result dom_adjacent_position_str_to_enum(zend_enum_Dom_AdjacentPosition *value, const zend_string *str) +{ + if (zend_string_equals_literal_ci(str, "beforebegin")) { + *value = ZEND_ENUM_Dom_AdjacentPosition_BeforeBegin; + } else if (zend_string_equals_literal_ci(str, "afterbegin")) { + *value = ZEND_ENUM_Dom_AdjacentPosition_AfterBegin; + } else if (zend_string_equals_literal_ci(str, "beforeend")) { + *value = ZEND_ENUM_Dom_AdjacentPosition_BeforeEnd; + } else if (zend_string_equals_literal_ci(str, "afterend")) { + *value = ZEND_ENUM_Dom_AdjacentPosition_AfterEnd; + } else { + return FAILURE; + } + + return SUCCESS; +} + PHP_METHOD(DOMElement, insertAdjacentElement) { - zend_string *where; + zend_string *where_str; + zend_enum_Dom_AdjacentPosition where; zval *element_zval; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SO", &where, &element_zval, dom_element_class_entry) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SO", &where_str, &element_zval, dom_element_class_entry) != SUCCESS) { + RETURN_THROWS(); + } + + if (dom_adjacent_position_str_to_enum(&where, where_str) != SUCCESS) { + zval *id; + xmlNodePtr p; + dom_object *intern; + DOM_GET_THIS_OBJ(p, id, xmlNodePtr, intern); + (void)p; + + php_dom_throw_error(SYNTAX_ERR, dom_get_strict_error(intern->document)); RETURN_THROWS(); } @@ -1680,14 +1711,14 @@ PHP_METHOD(DOMElement, insertAdjacentElement) PHP_METHOD(Dom_Element, insertAdjacentElement) { - zval *element_zval, *where_zv; + zend_enum_Dom_AdjacentPosition where; + zval *element_zval; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_OBJECT_OF_CLASS(where_zv, dom_adjacent_position_class_entry) + Z_PARAM_ENUM(where, dom_adjacent_position_class_entry) Z_PARAM_OBJECT_OF_CLASS(element_zval, dom_modern_element_class_entry) ZEND_PARSE_PARAMETERS_END(); - const zend_string *where = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(where_zv))); dom_element_insert_adjacent_element(INTERNAL_FUNCTION_PARAM_PASSTHRU, where, element_zval); } /* }}} end DOMElement::insertAdjacentElement */ @@ -1695,7 +1726,7 @@ PHP_METHOD(Dom_Element, insertAdjacentElement) /* {{{ URL: https://dom.spec.whatwg.org/#dom-element-insertadjacenttext Since: */ -static void dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAMETERS, const zend_string *where, const zend_string *data) +static void dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAMETERS, zend_enum_Dom_AdjacentPosition where, const zend_string *data) { dom_object *this_intern; zval *id; @@ -1717,9 +1748,21 @@ static void dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAMETERS, const PHP_METHOD(DOMElement, insertAdjacentText) { - zend_string *where, *data; + zend_string *where_str, *data; + zend_enum_Dom_AdjacentPosition where; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &where, &data) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &where_str, &data) == FAILURE) { + RETURN_THROWS(); + } + + if (dom_adjacent_position_str_to_enum(&where, where_str) != SUCCESS) { + zval *id; + xmlNodePtr p; + dom_object *intern; + DOM_GET_THIS_OBJ(p, id, xmlNodePtr, intern); + (void)p; + + php_dom_throw_error(SYNTAX_ERR, dom_get_strict_error(intern->document)); RETURN_THROWS(); } @@ -1728,15 +1771,14 @@ PHP_METHOD(DOMElement, insertAdjacentText) PHP_METHOD(Dom_Element, insertAdjacentText) { - zval *where_zv; + zend_enum_Dom_AdjacentPosition where; zend_string *data; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_OBJECT_OF_CLASS(where_zv, dom_adjacent_position_class_entry) + Z_PARAM_ENUM(where, dom_adjacent_position_class_entry) Z_PARAM_STR(data) ZEND_PARSE_PARAMETERS_END(); - const zend_string *where = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(where_zv))); dom_element_insert_adjacent_text(INTERNAL_FUNCTION_PARAM_PASSTHRU, where, data); } /* }}} end DOMElement::insertAdjacentText */ @@ -1744,7 +1786,7 @@ PHP_METHOD(Dom_Element, insertAdjacentText) /* https://html.spec.whatwg.org/#dom-element-insertadjacenthtml */ PHP_METHOD(Dom_Element, insertAdjacentHTML) { - zval *where_zv; + zend_enum_Dom_AdjacentPosition where; zend_string *string; dom_object *this_intern; @@ -1754,23 +1796,21 @@ PHP_METHOD(Dom_Element, insertAdjacentHTML) bool created_context = false; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_OBJECT_OF_CLASS(where_zv, dom_adjacent_position_class_entry) + Z_PARAM_ENUM(where, dom_adjacent_position_class_entry) Z_PARAM_STR(string) ZEND_PARSE_PARAMETERS_END(); DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, this_intern); - const zend_string *where = Z_STR_P(zend_enum_fetch_case_name(Z_OBJ_P(where_zv))); - /* 1. We don't do injection sinks. */ /* 2. Let context be NULL */ xmlNodePtr context = NULL; /* 3. Use the first matching item from this list: (...) */ - switch (ZSTR_LEN(where) + ZSTR_VAL(where)[2]) { - case sizeof("BeforeBegin") - 1 + 'f': - case sizeof("AfterEnd") - 1 + 't': + switch (where) { + case ZEND_ENUM_Dom_AdjacentPosition_BeforeBegin: + case ZEND_ENUM_Dom_AdjacentPosition_AfterEnd: /* 1. Set context to this's parent. */ context = thisp->parent; @@ -1780,8 +1820,8 @@ PHP_METHOD(Dom_Element, insertAdjacentHTML) RETURN_THROWS(); } break; - case sizeof("AfterBegin") - 1 + 't': - case sizeof("BeforeEnd") - 1 + 'f': + case ZEND_ENUM_Dom_AdjacentPosition_AfterBegin: + case ZEND_ENUM_Dom_AdjacentPosition_BeforeEnd: /* Set context to this. */ context = thisp; break; @@ -1811,17 +1851,17 @@ PHP_METHOD(Dom_Element, insertAdjacentHTML) php_libxml_invalidate_node_list_cache(this_intern->document); /* 6. Use the first matching item from this list: (...) */ - switch (ZSTR_LEN(where) + ZSTR_VAL(where)[2]) { - case sizeof("BeforeBegin") - 1 + 'f': + switch (where) { + case ZEND_ENUM_Dom_AdjacentPosition_BeforeBegin: php_dom_pre_insert(this_intern->document, fragment, thisp->parent, thisp); break; - case sizeof("AfterEnd") - 1 + 't': + case ZEND_ENUM_Dom_AdjacentPosition_AfterEnd: php_dom_pre_insert(this_intern->document, fragment, thisp->parent, thisp->next); break; - case sizeof("AfterBegin") - 1 + 't': + case ZEND_ENUM_Dom_AdjacentPosition_AfterBegin: php_dom_pre_insert(this_intern->document, fragment, thisp, thisp->children); break; - case sizeof("BeforeEnd") - 1 + 'f': + case ZEND_ENUM_Dom_AdjacentPosition_BeforeEnd: php_dom_node_append(this_intern->document, fragment, thisp); break; EMPTY_SWITCH_DEFAULT_CASE(); diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index e44f74eadeb37..e93000044f00e 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -54,6 +54,7 @@ extern zend_module_entry dom_module_entry; #include "xpath_callbacks.h" #include "zend_exceptions.h" #include "dom_ce.h" +#include "php_dom_decl.h" /* DOM API_VERSION, please bump it up, if you change anything in the API therefore it's easier for the script-programmers to check, what's working how diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 37a1bea62b627..71aa5f4ec0faf 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -1,6 +1,9 @@ engine, min, max)); - case 'C' + sizeof("ClosedClosed") - 1: + case ZEND_ENUM_Random_IntervalBoundary_ClosedClosed: if (UNEXPECTED(max < min)) { zend_argument_value_error(2, "must be greater than or equal to argument #1 ($min)"); RETURN_THROWS(); } RETURN_DOUBLE(php_random_gammasection_closed_closed(randomizer->engine, min, max)); - case 'O' + sizeof("OpenClosed") - 1: + case ZEND_ENUM_Random_IntervalBoundary_OpenClosed: if (UNEXPECTED(max <= min)) { zend_argument_value_error(2, "must be greater than argument #1 ($min)"); RETURN_THROWS(); } RETURN_DOUBLE(php_random_gammasection_open_closed(randomizer->engine, min, max)); - case 'O' + sizeof("OpenOpen") - 1: + case ZEND_ENUM_Random_IntervalBoundary_OpenOpen: if (UNEXPECTED(max <= min)) { zend_argument_value_error(2, "must be greater than argument #1 ($min)"); RETURN_THROWS(); @@ -194,8 +186,6 @@ PHP_METHOD(Random_Randomizer, getFloat) } return; - default: - ZEND_UNREACHABLE(); } } /* }}} */ diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 64e79651913fb..256468e39a444 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6547,16 +6547,16 @@ ZEND_METHOD(ReflectionProperty, hasHook) reflection_object *intern; property_reference *ref; - zend_object *type; + zend_enum_PropertyHookType type; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJ_OF_CLASS(type, reflection_property_hook_type_ptr) + Z_PARAM_ENUM(type, reflection_property_hook_type_ptr) ZEND_PARSE_PARAMETERS_END(); GET_REFLECTION_OBJECT_PTR(ref); zend_property_hook_kind kind; - if (zend_string_equals_literal(Z_STR_P(zend_enum_fetch_case_name(type)), "Get")) { + if (type == ZEND_ENUM_PropertyHookType_Get) { kind = ZEND_PROPERTY_HOOK_GET; } else { kind = ZEND_PROPERTY_HOOK_SET; @@ -6569,10 +6569,10 @@ ZEND_METHOD(ReflectionProperty, getHook) { reflection_object *intern; property_reference *ref; - zend_object *type; + zend_enum_PropertyHookType type; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_OBJ_OF_CLASS(type, reflection_property_hook_type_ptr) + Z_PARAM_ENUM(type, reflection_property_hook_type_ptr) ZEND_PARSE_PARAMETERS_END(); GET_REFLECTION_OBJECT_PTR(ref); @@ -6583,7 +6583,7 @@ ZEND_METHOD(ReflectionProperty, getHook) } zend_function *hook; - if (zend_string_equals_literal(Z_STR_P(zend_enum_fetch_case_name(type)), "Get")) { + if (type == ZEND_ENUM_PropertyHookType_Get) { hook = ref->prop->hooks[ZEND_PROPERTY_HOOK_GET]; } else { hook = ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]; diff --git a/ext/reflection/php_reflection.h b/ext/reflection/php_reflection.h index d676597fd0bed..dc22407342985 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -18,6 +18,7 @@ #define PHP_REFLECTION_H #include "php.h" +#include "php_reflection_decl.h" extern zend_module_entry reflection_module_entry; #define phpext_reflection_ptr &reflection_module_entry diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 91c70d6ffdb1a..147e2f18c9e2c 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -1,6 +1,9 @@ #endif diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 4f77cf9b7f8ef..6fa0d47c7bd7f 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1,6 +1,9 @@ std.ce->name)); } -static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_object *comparison_mode) +static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_enum_Uri_UriComparisonMode comparison_mode) { php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS); ZEND_ASSERT(this_object->uri != NULL); @@ -691,11 +691,7 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object RETURN_FALSE; } - bool exclude_fragment = true; - if (comparison_mode) { - zval *case_name = zend_enum_fetch_case_name(comparison_mode); - exclude_fragment = zend_string_equals_literal(Z_STR_P(case_name), "ExcludeFragment"); - } + bool exclude_fragment = comparison_mode == ZEND_ENUM_Uri_UriComparisonMode_ExcludeFragment; zend_string *this_str = this_object->parser->to_string( this_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment); @@ -721,12 +717,12 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object PHP_METHOD(Uri_Rfc3986_Uri, equals) { zend_object *that_object; - zend_object *comparison_mode = NULL; + zend_enum_Uri_UriComparisonMode comparison_mode = ZEND_ENUM_Uri_UriComparisonMode_ExcludeFragment; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_OBJ_OF_CLASS(that_object, php_uri_ce_rfc3986_uri) Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode) + Z_PARAM_ENUM(comparison_mode, php_uri_ce_comparison_mode) ZEND_PARSE_PARAMETERS_END(); uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode); @@ -917,12 +913,12 @@ PHP_METHOD(Uri_WhatWg_Url, getFragment) PHP_METHOD(Uri_WhatWg_Url, equals) { zend_object *that_object; - zend_object *comparison_mode = NULL; + zend_enum_Uri_UriComparisonMode comparison_mode = ZEND_ENUM_Uri_UriComparisonMode_ExcludeFragment; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_OBJ_OF_CLASS(that_object, php_uri_ce_whatwg_url) Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode) + Z_PARAM_ENUM(comparison_mode, php_uri_ce_comparison_mode) ZEND_PARSE_PARAMETERS_END(); uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode); diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index 9f12fbb1c0701..6d4b2c3517a5e 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -1,6 +1,9 @@