From b61954a10a8f1894299ea4b845198c796f04633c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sat, 30 May 2020 16:59:20 +0200 Subject: [PATCH 1/7] Add ZPP macros for string|object parameters --- Zend/tests/010.phpt | 8 +++- Zend/zend_API.h | 37 +++++++++++++++++++ Zend/zend_builtin_functions.c | 22 +++++------ Zend/zend_builtin_functions.stub.php | 2 +- Zend/zend_builtin_functions_arginfo.h | 2 +- .../get_parent_class_variation_002.phpt | 28 +++++++++----- 6 files changed, 75 insertions(+), 24 deletions(-) diff --git a/Zend/tests/010.phpt b/Zend/tests/010.phpt index a4a862cac220..91a8fa5ba26a 100644 --- a/Zend/tests/010.phpt +++ b/Zend/tests/010.phpt @@ -36,7 +36,11 @@ var_dump(get_parent_class("")); var_dump(get_parent_class("[[[[")); var_dump(get_parent_class(" ")); var_dump(get_parent_class(new stdclass)); -var_dump(get_parent_class(array())); +try { + get_parent_class(array()); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} var_dump(get_parent_class(1)); echo "Done\n"; @@ -54,6 +58,6 @@ bool(false) bool(false) bool(false) bool(false) -bool(false) +get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given bool(false) Done diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 9744612ac746..ca94a804a137 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1217,6 +1217,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv) _(Z_EXPECTED_STRING_OR_ARRAY_OR_NULL, "of type string|array|null") \ _(Z_EXPECTED_STRING_OR_LONG, "of type string|int") \ _(Z_EXPECTED_STRING_OR_LONG_OR_NULL, "of type string|int|null") \ + _(Z_EXPECTED_STRING_OR_OBJECT, "of type string|object") \ + _(Z_EXPECTED_STRING_OR_OBJECT_OR_NULL, "of type string|object|null") \ #define Z_EXPECTED_TYPE @@ -1673,6 +1675,21 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_STR_OR_LONG_OR_NULL(dest_str, dest_long, is_null) \ Z_PARAM_STR_OR_LONG_EX(dest_str, dest_long, is_null, 1); + +#define Z_PARAM_STR_OR_OBJECT_EX(dest_str, dest_object, allow_null) \ + Z_PARAM_PROLOGUE(0, 0); \ + if (UNEXPECTED(!zend_parse_arg_str_or_object(_arg, &dest_str, &dest_object, allow_null))) { \ + _expected_type = allow_null ? Z_EXPECTED_STRING_OR_OBJECT_OR_NULL : Z_EXPECTED_STRING_OR_OBJECT; \ + _error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } + +#define Z_PARAM_STR_OR_OBJECT(dest_str, dest_object) \ + Z_PARAM_STR_OR_OBJECT_EX(dest_str, dest_object, 0); + +#define Z_PARAM_STR_OR_OBJECT_OR_NULL(dest_str, dest_object) \ + Z_PARAM_STR_OR_OBJECT_EX(dest_str, dest_object, 1); + /* End of new parameter parsing API */ /* Inlined implementations shared by new and old parameter parsing APIs */ @@ -1931,6 +1948,26 @@ static zend_always_inline int zend_parse_arg_str_or_long(zval *arg, zend_string return 1; } +static zend_always_inline int zend_parse_arg_str_or_object( + zval *arg, zend_string **dest_str, zend_object **dest_object, int allow_null +) { + if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { + *dest_str = Z_STR_P(arg); + *dest_object = NULL; + } else if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { + *dest_object = Z_OBJ_P(arg); + *dest_str = NULL; + } else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) { + *dest_object = NULL; + *dest_str = NULL; + } else { + *dest_object = NULL; + return zend_parse_arg_str_slow(arg, dest_str); + } + + return 1; +} + END_EXTERN_C() #endif /* ZEND_API_H */ diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 521c2c32de19..0753f5653cbc 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -637,14 +637,20 @@ ZEND_FUNCTION(get_called_class) Retrieves the parent class name for object or class or current scope or false if not in a scope. */ ZEND_FUNCTION(get_parent_class) { - zval *arg; + zend_string *str = NULL; + zend_object *object = NULL; zend_class_entry *ce = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_OBJECT_OR_NULL(str, object) + ZEND_PARSE_PARAMETERS_END(); - if (!ZEND_NUM_ARGS()) { + if (object) { + ce = object->ce; + } else if (str) { + ce = zend_lookup_class(str); + } else { ce = zend_get_executed_scope(); if (ce && ce->parent) { RETURN_STR_COPY(ce->parent->name); @@ -653,12 +659,6 @@ ZEND_FUNCTION(get_parent_class) } } - if (Z_TYPE_P(arg) == IS_OBJECT) { - ce = Z_OBJ_P(arg)->ce; - } else if (Z_TYPE_P(arg) == IS_STRING) { - ce = zend_lookup_class(Z_STR_P(arg)); - } - if (ce && ce->parent) { RETURN_STR_COPY(ce->parent->name); } else { diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index 9e5078f14a9c..3e33523059c8 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -30,7 +30,7 @@ function get_class(object $object = UNKNOWN): string {} function get_called_class(): string {} -function get_parent_class($object = UNKNOWN): string|false {} +function get_parent_class(string|object|null $object = null): string|false {} function is_subclass_of($object, string $class_name, bool $allow_string = true): bool {} diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index df1f06888ee9..0b96a4dbacfe 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -54,7 +54,7 @@ ZEND_END_ARG_INFO() #define arginfo_get_called_class arginfo_zend_version ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_get_parent_class, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_INFO(0, object) + ZEND_ARG_TYPE_MASK(0, object, MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_is_subclass_of, 0, 2, _IS_BOOL, 0) diff --git a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt index 8d3e64e92515..7999e48a063f 100644 --- a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt +++ b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt @@ -70,10 +70,14 @@ $values = array( // loop through each element of the array for object -foreach($values as $value) { - echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . " \n"; - var_dump( get_parent_class($value) ); -}; +foreach ($values as $value) { + echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . " \n"; + try { + var_dump(get_parent_class($value)); + } catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; + } +} echo "Done"; ?> @@ -83,12 +87,15 @@ Error: 2 - Undefined variable $undefined_var Error: 2 - Undefined variable $unset_var Arg value 0 +In autoload(0) bool(false) Arg value 1 +In autoload(1) bool(false) Arg value 12345 +In autoload(12345) bool(false) Arg value -2345 @@ -101,6 +108,7 @@ Arg value -10.5 bool(false) Arg value 101234567000 +In autoload(101234567000) bool(false) Arg value 1.07654321E-9 @@ -111,23 +119,23 @@ bool(false) Error: 2 - Array to string conversion Arg value Array -bool(false) +get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given Error: 2 - Array to string conversion Arg value Array -bool(false) +get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given Error: 2 - Array to string conversion Arg value Array -bool(false) +get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given Error: 2 - Array to string conversion Arg value Array -bool(false) +get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given Error: 2 - Array to string conversion Arg value Array -bool(false) +get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given Arg value bool(false) @@ -136,12 +144,14 @@ Arg value bool(false) Arg value 1 +In autoload(1) bool(false) Arg value bool(false) Arg value 1 +In autoload(1) bool(false) Arg value From 8070705c2fb449178e21c3b510b20c1894aecae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sat, 30 May 2020 19:56:45 +0200 Subject: [PATCH 2/7] Add convenience macros for ZPP validation of nullable objects --- Zend/zend_API.h | 6 ++++++ ext/date/php_date.c | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index ca94a804a137..fa81e1e0a91e 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1515,6 +1515,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_OBJECT(dest) \ Z_PARAM_OBJECT_EX(dest, 0, 0) +#define Z_PARAM_OBJECT_OR_NULL(dest) \ + Z_PARAM_OBJECT_EX(dest, 1, 0) + /* old "O" */ #define Z_PARAM_OBJECT_OF_CLASS_EX2(dest, _ce, check_null, deref, separate) \ Z_PARAM_PROLOGUE(deref, separate); \ @@ -1536,6 +1539,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_OBJECT_OF_CLASS(dest, _ce) \ Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 0, 0) +#define Z_PARAM_OBJECT_OF_CLASS_OR_NULL(dest, _ce) \ + Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 1, 0) + /* old "p" */ #define Z_PARAM_PATH_EX2(dest, dest_len, check_null, deref, separate) \ Z_PARAM_PROLOGUE(deref, separate); \ diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0b4520566fe0..6813b60e624c 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2295,7 +2295,7 @@ PHP_FUNCTION(date_create) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_STRING(time_str, time_str_len) - Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); php_date_instantiate(date_ce_date, return_value); @@ -2318,7 +2318,7 @@ PHP_FUNCTION(date_create_immutable) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_STRING(time_str, time_str_len) - Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); php_date_instantiate(date_ce_immutable, return_value); @@ -2342,7 +2342,7 @@ PHP_FUNCTION(date_create_from_format) Z_PARAM_STRING(format_str, format_str_len) Z_PARAM_STRING(time_str, time_str_len) Z_PARAM_OPTIONAL - Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); php_date_instantiate(date_ce_date, return_value); @@ -2366,7 +2366,7 @@ PHP_FUNCTION(date_create_immutable_from_format) Z_PARAM_STRING(format_str, format_str_len) Z_PARAM_STRING(time_str, time_str_len) Z_PARAM_OPTIONAL - Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); php_date_instantiate(date_ce_immutable, return_value); @@ -2390,7 +2390,7 @@ PHP_METHOD(DateTime, __construct) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_STRING(time_str, time_str_len) - Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); zend_replace_error_handling(EH_THROW, NULL, &error_handling); @@ -2412,7 +2412,7 @@ PHP_METHOD(DateTimeImmutable, __construct) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_STRING(time_str, time_str_len) - Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); zend_replace_error_handling(EH_THROW, NULL, &error_handling); From c6012d5695aa8b807a4a8a5ff16bd7d25e5c2e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sun, 31 May 2020 00:06:42 +0200 Subject: [PATCH 3/7] Rename macro --- Zend/zend_API.h | 14 +++++++------- Zend/zend_builtin_functions.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index fa81e1e0a91e..38cb51f20191 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1682,19 +1682,19 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_STR_OR_LONG_OR_NULL(dest_str, dest_long, is_null) \ Z_PARAM_STR_OR_LONG_EX(dest_str, dest_long, is_null, 1); -#define Z_PARAM_STR_OR_OBJECT_EX(dest_str, dest_object, allow_null) \ +#define Z_PARAM_STR_OR_OBJ_EX(dest_str, dest_object, allow_null) \ Z_PARAM_PROLOGUE(0, 0); \ - if (UNEXPECTED(!zend_parse_arg_str_or_object(_arg, &dest_str, &dest_object, allow_null))) { \ + if (UNEXPECTED(!zend_parse_arg_str_or_obj(_arg, &dest_str, &dest_object, allow_null))) { \ _expected_type = allow_null ? Z_EXPECTED_STRING_OR_OBJECT_OR_NULL : Z_EXPECTED_STRING_OR_OBJECT; \ _error_code = ZPP_ERROR_WRONG_ARG; \ break; \ } -#define Z_PARAM_STR_OR_OBJECT(dest_str, dest_object) \ - Z_PARAM_STR_OR_OBJECT_EX(dest_str, dest_object, 0); +#define Z_PARAM_STR_OR_OBJ(dest_str, dest_object) \ + Z_PARAM_STR_OR_OBJ_EX(dest_str, dest_object, 0); -#define Z_PARAM_STR_OR_OBJECT_OR_NULL(dest_str, dest_object) \ - Z_PARAM_STR_OR_OBJECT_EX(dest_str, dest_object, 1); +#define Z_PARAM_STR_OR_OBJ_OR_NULL(dest_str, dest_object) \ + Z_PARAM_STR_OR_OBJ_EX(dest_str, dest_object, 1); /* End of new parameter parsing API */ @@ -1954,7 +1954,7 @@ static zend_always_inline int zend_parse_arg_str_or_long(zval *arg, zend_string return 1; } -static zend_always_inline int zend_parse_arg_str_or_object( +static zend_always_inline int zend_parse_arg_str_or_obj( zval *arg, zend_string **dest_str, zend_object **dest_object, int allow_null ) { if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 0753f5653cbc..b49d10f1d7dd 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -643,7 +643,7 @@ ZEND_FUNCTION(get_parent_class) ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL - Z_PARAM_STR_OR_OBJECT_OR_NULL(str, object) + Z_PARAM_STR_OR_OBJ_OR_NULL(str, object) ZEND_PARSE_PARAMETERS_END(); if (object) { From 0b86dcbc4fabfe5b626db6defe8ea5ba0919f944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 3 Jun 2020 18:48:49 +0200 Subject: [PATCH 4/7] Remove the duplicated condition --- Zend/zend_builtin_functions.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index b49d10f1d7dd..a0cb4f07f2e4 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -652,11 +652,6 @@ ZEND_FUNCTION(get_parent_class) ce = zend_lookup_class(str); } else { ce = zend_get_executed_scope(); - if (ce && ce->parent) { - RETURN_STR_COPY(ce->parent->name); - } else { - RETURN_FALSE; - } } if (ce && ce->parent) { From 2328b3f815612fe0f4a46d0b7806a84f27796c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 3 Jun 2020 19:15:07 +0200 Subject: [PATCH 5/7] Remove support for a null default value --- Zend/tests/010.phpt | 2 +- Zend/zend_builtin_functions.c | 2 +- Zend/zend_builtin_functions.stub.php | 2 +- Zend/zend_builtin_functions_arginfo.h | 2 +- .../get_parent_class_variation_002.phpt | 66 +++++++++---------- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Zend/tests/010.phpt b/Zend/tests/010.phpt index 91a8fa5ba26a..b1ce37afff9e 100644 --- a/Zend/tests/010.phpt +++ b/Zend/tests/010.phpt @@ -58,6 +58,6 @@ bool(false) bool(false) bool(false) bool(false) -get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given +get_parent_class(): Argument #1 ($object) must be of type string|object, array given bool(false) Done diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index a0cb4f07f2e4..8ac618c546e9 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -643,7 +643,7 @@ ZEND_FUNCTION(get_parent_class) ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL - Z_PARAM_STR_OR_OBJ_OR_NULL(str, object) + Z_PARAM_STR_OR_OBJ(str, object) ZEND_PARSE_PARAMETERS_END(); if (object) { diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index 3e33523059c8..a79aced5fed7 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -30,7 +30,7 @@ function get_class(object $object = UNKNOWN): string {} function get_called_class(): string {} -function get_parent_class(string|object|null $object = null): string|false {} +function get_parent_class(string|object $object = UNKNOWN): string|false {} function is_subclass_of($object, string $class_name, bool $allow_string = true): bool {} diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index 0b96a4dbacfe..c464a540a1ff 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -54,7 +54,7 @@ ZEND_END_ARG_INFO() #define arginfo_get_called_class arginfo_zend_version ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_get_parent_class, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_TYPE_MASK(0, object, MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_NULL, "null") + ZEND_ARG_TYPE_MASK(0, object, MAY_BE_STRING|MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_is_subclass_of, 0, 2, _IS_BOOL, 0) diff --git a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt index 7999e48a063f..4d8814e6d062 100644 --- a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt +++ b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt @@ -71,7 +71,7 @@ $values = array( // loop through each element of the array for object foreach ($values as $value) { - echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . " \n"; + echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . "\n"; try { var_dump(get_parent_class($value)); } catch (TypeError $exception) { @@ -86,97 +86,97 @@ echo "Done"; Error: 2 - Undefined variable $undefined_var Error: 2 - Undefined variable $unset_var -Arg value 0 +Arg value 0 In autoload(0) bool(false) -Arg value 1 +Arg value 1 In autoload(1) bool(false) -Arg value 12345 +Arg value 12345 In autoload(12345) bool(false) -Arg value -2345 +Arg value -2345 bool(false) -Arg value 10.5 +Arg value 10.5 bool(false) -Arg value -10.5 +Arg value -10.5 bool(false) -Arg value 101234567000 +Arg value 101234567000 In autoload(101234567000) bool(false) -Arg value 1.07654321E-9 +Arg value 1.07654321E-9 bool(false) -Arg value 0.5 +Arg value 0.5 bool(false) Error: 2 - Array to string conversion -Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given +Arg value Array +get_parent_class(): Argument #1 ($object) must be of type string|object, array given Error: 2 - Array to string conversion -Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given +Arg value Array +get_parent_class(): Argument #1 ($object) must be of type string|object, array given Error: 2 - Array to string conversion -Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given +Arg value Array +get_parent_class(): Argument #1 ($object) must be of type string|object, array given Error: 2 - Array to string conversion -Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given +Arg value Array +get_parent_class(): Argument #1 ($object) must be of type string|object, array given Error: 2 - Array to string conversion -Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object|null, array given +Arg value Array +get_parent_class(): Argument #1 ($object) must be of type string|object, array given -Arg value +Arg value bool(false) -Arg value +Arg value bool(false) -Arg value 1 +Arg value 1 In autoload(1) bool(false) -Arg value +Arg value bool(false) -Arg value 1 +Arg value 1 In autoload(1) bool(false) -Arg value +Arg value bool(false) -Arg value +Arg value bool(false) -Arg value +Arg value bool(false) -Arg value string +Arg value string In autoload(string) bool(false) -Arg value String +Arg value String In autoload(String) bool(false) -Arg value stdClass +Arg value stdClass bool(false) -Arg value +Arg value bool(false) -Arg value +Arg value bool(false) Done From d8e33aa41bbcdc7c678d5850669e235def55b9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Mon, 22 Jun 2020 16:43:26 +0200 Subject: [PATCH 6/7] Change the new macro to Z_PARAM_CLASS_NAME_OR_OBJ --- Zend/tests/010.phpt | 39 +++++++++++++++++++++------- Zend/zend_API.h | 49 +++++++++++++++++++---------------- Zend/zend_builtin_functions.c | 2 +- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/Zend/tests/010.phpt b/Zend/tests/010.phpt index b1ce37afff9e..351398ecfa85 100644 --- a/Zend/tests/010.phpt +++ b/Zend/tests/010.phpt @@ -32,16 +32,37 @@ var_dump(get_parent_class("bar")); var_dump(get_parent_class("foo")); var_dump(get_parent_class("i")); -var_dump(get_parent_class("")); -var_dump(get_parent_class("[[[[")); -var_dump(get_parent_class(" ")); +try { + get_parent_class(""); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + get_parent_class("[[[["); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + get_parent_class(" "); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + var_dump(get_parent_class(new stdclass)); + try { get_parent_class(array()); } catch (TypeError $exception) { echo $exception->getMessage() . "\n"; } -var_dump(get_parent_class(1)); + +try { + get_parent_class(1); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} echo "Done\n"; ?> @@ -54,10 +75,10 @@ bool(false) string(3) "foo" bool(false) bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given bool(false) -bool(false) -bool(false) -bool(false) -get_parent_class(): Argument #1 ($object) must be of type string|object, array given -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given Done diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 38cb51f20191..bd6723013f10 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1217,8 +1217,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv) _(Z_EXPECTED_STRING_OR_ARRAY_OR_NULL, "of type string|array|null") \ _(Z_EXPECTED_STRING_OR_LONG, "of type string|int") \ _(Z_EXPECTED_STRING_OR_LONG_OR_NULL, "of type string|int|null") \ - _(Z_EXPECTED_STRING_OR_OBJECT, "of type string|object") \ - _(Z_EXPECTED_STRING_OR_OBJECT_OR_NULL, "of type string|object|null") \ + _(Z_EXPECTED_CLASS_NAME_OR_OBJECT, "a valid class name or object") \ + _(Z_EXPECTED_CLASS_NAME_OR_OBJECT_OR_NULL, "a valid class name, object, or null") \ #define Z_EXPECTED_TYPE @@ -1397,6 +1397,20 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_CLASS(dest) \ Z_PARAM_CLASS_EX(dest, 0, 0) +#define Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest_str, dest_object, allow_null) \ + Z_PARAM_PROLOGUE(0, 0); \ + if (UNEXPECTED(!zend_parse_arg_class_name_or_obj(_arg, &dest_str, &dest_object, _i, allow_null))) { \ + _expected_type = allow_null ? Z_EXPECTED_CLASS_NAME_OR_OBJECT_OR_NULL : Z_EXPECTED_CLASS_NAME_OR_OBJECT; \ + _error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } + +#define Z_PARAM_CLASS_NAME_OR_OBJ(dest_str, dest_object) \ + Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest_str, dest_object, 0); + +#define Z_PARAM_CLASS_NAME_OR_OBJ_OR_NULL(dest_str, dest_object) \ + Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest_str, dest_object, 1); + /* old "d" */ #define Z_PARAM_DOUBLE_EX2(dest, is_null, check_null, deref, separate) \ Z_PARAM_PROLOGUE(deref, separate); \ @@ -1682,20 +1696,6 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_STR_OR_LONG_OR_NULL(dest_str, dest_long, is_null) \ Z_PARAM_STR_OR_LONG_EX(dest_str, dest_long, is_null, 1); -#define Z_PARAM_STR_OR_OBJ_EX(dest_str, dest_object, allow_null) \ - Z_PARAM_PROLOGUE(0, 0); \ - if (UNEXPECTED(!zend_parse_arg_str_or_obj(_arg, &dest_str, &dest_object, allow_null))) { \ - _expected_type = allow_null ? Z_EXPECTED_STRING_OR_OBJECT_OR_NULL : Z_EXPECTED_STRING_OR_OBJECT; \ - _error_code = ZPP_ERROR_WRONG_ARG; \ - break; \ - } - -#define Z_PARAM_STR_OR_OBJ(dest_str, dest_object) \ - Z_PARAM_STR_OR_OBJ_EX(dest_str, dest_object, 0); - -#define Z_PARAM_STR_OR_OBJ_OR_NULL(dest_str, dest_object) \ - Z_PARAM_STR_OR_OBJ_EX(dest_str, dest_object, 1); - /* End of new parameter parsing API */ /* Inlined implementations shared by new and old parameter parsing APIs */ @@ -1954,21 +1954,24 @@ static zend_always_inline int zend_parse_arg_str_or_long(zval *arg, zend_string return 1; } -static zend_always_inline int zend_parse_arg_str_or_obj( - zval *arg, zend_string **dest_str, zend_object **dest_object, int allow_null +static zend_always_inline int zend_parse_arg_class_name_or_obj( + zval *arg, zend_string **dest_str, zend_object **dest_object, int num, int allow_null ) { - if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { - *dest_str = Z_STR_P(arg); + zend_class_entry *class_entry; + + if (EXPECTED(Z_TYPE_P(arg) == IS_STRING) && (class_entry = zend_lookup_class(Z_STR_P(arg)))) { + *dest_str = class_entry->name; *dest_object = NULL; } else if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { - *dest_object = Z_OBJ_P(arg); *dest_str = NULL; + *dest_object = Z_OBJ_P(arg); } else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) { - *dest_object = NULL; *dest_str = NULL; + *dest_object = NULL; } else { + *dest_str = NULL; *dest_object = NULL; - return zend_parse_arg_str_slow(arg, dest_str); + return 0; } return 1; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 8ac618c546e9..87cb816429fa 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -643,7 +643,7 @@ ZEND_FUNCTION(get_parent_class) ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL - Z_PARAM_STR_OR_OBJ(str, object) + Z_PARAM_CLASS_NAME_OR_OBJ(str, object) ZEND_PARSE_PARAMETERS_END(); if (object) { From 99b10761af8006fb27647d6abc85202287318e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 30 Jun 2020 09:16:27 +0200 Subject: [PATCH 7/7] Fix destination --- Zend/zend_API.h | 30 +++++----- Zend/zend_builtin_functions.c | 10 +--- .../get_parent_class_variation_002.phpt | 58 +++++++++---------- 3 files changed, 41 insertions(+), 57 deletions(-) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index bd6723013f10..39c4be3e0d02 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1397,19 +1397,19 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num #define Z_PARAM_CLASS(dest) \ Z_PARAM_CLASS_EX(dest, 0, 0) -#define Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest_str, dest_object, allow_null) \ +#define Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, allow_null) \ Z_PARAM_PROLOGUE(0, 0); \ - if (UNEXPECTED(!zend_parse_arg_class_name_or_obj(_arg, &dest_str, &dest_object, _i, allow_null))) { \ + if (UNEXPECTED(!zend_parse_arg_class_name_or_obj(_arg, &dest, _i, allow_null))) { \ _expected_type = allow_null ? Z_EXPECTED_CLASS_NAME_OR_OBJECT_OR_NULL : Z_EXPECTED_CLASS_NAME_OR_OBJECT; \ _error_code = ZPP_ERROR_WRONG_ARG; \ break; \ } -#define Z_PARAM_CLASS_NAME_OR_OBJ(dest_str, dest_object) \ - Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest_str, dest_object, 0); +#define Z_PARAM_CLASS_NAME_OR_OBJ(dest) \ + Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, 0); -#define Z_PARAM_CLASS_NAME_OR_OBJ_OR_NULL(dest_str, dest_object) \ - Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest_str, dest_object, 1); +#define Z_PARAM_CLASS_NAME_OR_OBJ_OR_NULL(dest) \ + Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, 1); /* old "d" */ #define Z_PARAM_DOUBLE_EX2(dest, is_null, check_null, deref, separate) \ @@ -1955,22 +1955,18 @@ static zend_always_inline int zend_parse_arg_str_or_long(zval *arg, zend_string } static zend_always_inline int zend_parse_arg_class_name_or_obj( - zval *arg, zend_string **dest_str, zend_object **dest_object, int num, int allow_null + zval *arg, zend_class_entry **destination, int num, int allow_null ) { - zend_class_entry *class_entry; + if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { + *destination = zend_lookup_class(Z_STR_P(arg)); - if (EXPECTED(Z_TYPE_P(arg) == IS_STRING) && (class_entry = zend_lookup_class(Z_STR_P(arg)))) { - *dest_str = class_entry->name; - *dest_object = NULL; + return *destination != NULL; } else if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { - *dest_str = NULL; - *dest_object = Z_OBJ_P(arg); + *destination = Z_OBJ_P(arg)->ce; } else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) { - *dest_str = NULL; - *dest_object = NULL; + *destination = NULL; } else { - *dest_str = NULL; - *dest_object = NULL; + *destination = NULL; return 0; } diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 87cb816429fa..881624d321a8 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -637,20 +637,14 @@ ZEND_FUNCTION(get_called_class) Retrieves the parent class name for object or class or current scope or false if not in a scope. */ ZEND_FUNCTION(get_parent_class) { - zend_string *str = NULL; - zend_object *object = NULL; zend_class_entry *ce = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL - Z_PARAM_CLASS_NAME_OR_OBJ(str, object) + Z_PARAM_CLASS_NAME_OR_OBJ(ce) ZEND_PARSE_PARAMETERS_END(); - if (object) { - ce = object->ce; - } else if (str) { - ce = zend_lookup_class(str); - } else { + if (!ce) { ce = zend_get_executed_scope(); } diff --git a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt index 4d8814e6d062..a8c8e1711760 100644 --- a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt +++ b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt @@ -87,96 +87,90 @@ Error: 2 - Undefined variable $undefined_var Error: 2 - Undefined variable $unset_var Arg value 0 -In autoload(0) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given Arg value 1 -In autoload(1) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given Arg value 12345 -In autoload(12345) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given Arg value -2345 -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given Arg value 10.5 -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given Arg value -10.5 -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given Arg value 101234567000 -In autoload(101234567000) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given Arg value 1.07654321E-9 -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given Arg value 0.5 -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given Error: 2 - Array to string conversion Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object, array given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object, array given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object, array given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object, array given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion Arg value Array -get_parent_class(): Argument #1 ($object) must be of type string|object, array given +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given Arg value 1 -In autoload(1) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given Arg value 1 -In autoload(1) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given Arg value string In autoload(string) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given Arg value String In autoload(String) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given Arg value stdClass bool(false) Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given Arg value -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given Done