From f9d2e69b90583f955fed4a897346be5a4a698081 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 17 Feb 2025 19:06:14 -0800 Subject: [PATCH 1/4] Add #[NonpublicConstructor] attribute --- .../NonpublicConstructor/Generator.phpt | 13 ++ .../NonpublicConstructor/as_object.phpt | 14 ++ .../NonpublicConstructor/global_private.phpt | 18 ++ .../global_protected.phpt | 18 ++ .../must_be_constructor.phpt | 13 ++ .../must_be_nonpublic.phpt | 13 ++ .../NonpublicConstructor/non_string.phpt | 13 ++ .../subclass_private.phpt | 25 +++ .../subclass_without_new.phpt | 25 +++ .../NonpublicConstructor/without_message.phpt | 13 ++ Zend/zend_attributes.c | 133 ++++++++++++++ Zend/zend_attributes.h | 3 + Zend/zend_attributes.stub.php | 11 ++ Zend/zend_attributes_arginfo.h | 33 +++- Zend/zend_generators.c | 17 +- Zend/zend_generators.stub.php | 3 + Zend/zend_generators_arginfo.h | 16 +- Zend/zend_object_handlers.c | 22 ++- Zend/zend_vm_def.h | 14 +- Zend/zend_vm_execute.h | 168 ++++++++++++++++-- 20 files changed, 558 insertions(+), 27 deletions(-) create mode 100644 Zend/tests/attributes/NonpublicConstructor/Generator.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/as_object.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/global_private.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/global_protected.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/must_be_constructor.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/must_be_nonpublic.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/non_string.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/subclass_private.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/subclass_without_new.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/without_message.phpt diff --git a/Zend/tests/attributes/NonpublicConstructor/Generator.phpt b/Zend/tests/attributes/NonpublicConstructor/Generator.phpt new file mode 100644 index 0000000000000..2101de37edc37 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/Generator.phpt @@ -0,0 +1,13 @@ +--TEST-- +#[\NonpublicConstructor]: works as a replacement for get_constructor +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Call to private Generator::__construct() from global scope, the "Generator" class is reserved for internal use and cannot be manually instantiated, in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/NonpublicConstructor/as_object.phpt b/Zend/tests/attributes/NonpublicConstructor/as_object.phpt new file mode 100644 index 0000000000000..8d6ad0d0e5251 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/as_object.phpt @@ -0,0 +1,14 @@ +--TEST-- +#[\NonpublicConstructor]: using the attribute itself as an object +--FILE-- + +--EXPECTF-- +object(NonpublicConstructor)#%d (1) { + ["message"]=> + string(7) "example" +} diff --git a/Zend/tests/attributes/NonpublicConstructor/global_private.phpt b/Zend/tests/attributes/NonpublicConstructor/global_private.phpt new file mode 100644 index 0000000000000..30a73f98adeb2 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/global_private.phpt @@ -0,0 +1,18 @@ +--TEST-- +#[\NonpublicConstructor]: affects error message (private constructor, global scope) +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Call to private Demo::__construct() from global scope, use ::getInstance() instead, in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %s diff --git a/Zend/tests/attributes/NonpublicConstructor/global_protected.phpt b/Zend/tests/attributes/NonpublicConstructor/global_protected.phpt new file mode 100644 index 0000000000000..e7b2a29d7896c --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/global_protected.phpt @@ -0,0 +1,18 @@ +--TEST-- +#[\NonpublicConstructor]: affects error message (protected constructor, global scope) +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Call to protected Demo::__construct() from global scope, use ::getInstance() instead, in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %s diff --git a/Zend/tests/attributes/NonpublicConstructor/must_be_constructor.phpt b/Zend/tests/attributes/NonpublicConstructor/must_be_constructor.phpt new file mode 100644 index 0000000000000..b866704ddcdeb --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/must_be_constructor.phpt @@ -0,0 +1,13 @@ +--TEST-- +#[\NonpublicConstructor]: On a private non-constructor +--FILE-- + +--EXPECTF-- +Fatal error: #[NonpublicConstructor] can only be applied to constructors in %s on line %d diff --git a/Zend/tests/attributes/NonpublicConstructor/must_be_nonpublic.phpt b/Zend/tests/attributes/NonpublicConstructor/must_be_nonpublic.phpt new file mode 100644 index 0000000000000..5bf9381fb80da --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/must_be_nonpublic.phpt @@ -0,0 +1,13 @@ +--TEST-- +#[\NonpublicConstructor]: On a public constructor +--FILE-- + +--EXPECTF-- +Fatal error: #[NonpublicConstructor] can only be applied to protected or private constructors in %s on line %d diff --git a/Zend/tests/attributes/NonpublicConstructor/non_string.phpt b/Zend/tests/attributes/NonpublicConstructor/non_string.phpt new file mode 100644 index 0000000000000..5f5c4943173b6 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/non_string.phpt @@ -0,0 +1,13 @@ +--TEST-- +#[\NonpublicConstructor]: Message argument must be a string +--FILE-- + +--EXPECTF-- +Fatal error: NonpublicConstructor::__construct(): Argument #1 ($message) must be of type string, true given in %s on line %d diff --git a/Zend/tests/attributes/NonpublicConstructor/subclass_private.phpt b/Zend/tests/attributes/NonpublicConstructor/subclass_private.phpt new file mode 100644 index 0000000000000..a2e1e1708898d --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/subclass_private.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[\NonpublicConstructor]: affects error message (private constructor, protected scope) +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Call to private Demo::__construct() from scope Subclass, use ::getInstance() instead, in %s:%d +Stack trace: +#0 %s(%d): Subclass::create() +#1 {main} + thrown in %s on line %s diff --git a/Zend/tests/attributes/NonpublicConstructor/subclass_without_new.phpt b/Zend/tests/attributes/NonpublicConstructor/subclass_without_new.phpt new file mode 100644 index 0000000000000..1c62d2be9f666 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/subclass_without_new.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[\NonpublicConstructor]: affects error message (private constructor, protected scope, called via `parent::__construct()`) +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Cannot call private Demo::__construct(), use ::getInstance() instead, in %s:%d +Stack trace: +#0 %s(%d): Subclass->__construct() +#1 {main} + thrown in %s on line %s diff --git a/Zend/tests/attributes/NonpublicConstructor/without_message.phpt b/Zend/tests/attributes/NonpublicConstructor/without_message.phpt new file mode 100644 index 0000000000000..85579c29fac81 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/without_message.phpt @@ -0,0 +1,13 @@ +--TEST-- +#[\NonpublicConstructor]: Message argument is required +--FILE-- + +--EXPECTF-- +Fatal error: #[NonpublicConstructor] takes 1 parameter, 0 given in %s on line %d diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index d7bcb1f54e889..adcb4ab91f7da 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -31,6 +31,7 @@ ZEND_API zend_class_entry *zend_ce_sensitive_parameter; ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; ZEND_API zend_class_entry *zend_ce_override; ZEND_API zend_class_entry *zend_ce_deprecated; +ZEND_API zend_class_entry *zend_ce_nonpublic_constructor; static zend_object_handlers attributes_object_handlers_sensitive_parameter_value; @@ -94,6 +95,110 @@ static void validate_allow_dynamic_properties( scope->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; } +static void validate_nonpublic_constructor( + zend_attribute *attr, + uint32_t target, + zend_class_entry *scope +) { + zend_op_array *op_array = CG(active_op_array); + ZEND_ASSERT(op_array); + + if (!(op_array->fn_flags & ZEND_ACC_CTOR)) { + zend_error_noreturn( + E_ERROR, + "#[NonpublicConstructor] can only be applied to constructors" + ); + } + if (!(op_array->fn_flags & (ZEND_ACC_PROTECTED|ZEND_ACC_PRIVATE))) { + zend_error_noreturn( + E_ERROR, + "#[NonpublicConstructor] can only be applied to protected or private constructors" + ); + } + if (attr->argc != 1) { + zend_error_noreturn( + E_ERROR, + "#[NonpublicConstructor] takes 1 parameter, %d given", + attr->argc + ); + } + zval message; + if (FAILURE == zend_get_attribute_value(&message, attr, 0, NULL)) { + ZEND_ASSERT(EG(exception)); + return; + } + + if (Z_TYPE(message) != IS_STRING) { + zend_error_noreturn( + E_ERROR, + "NonpublicConstructor::__construct(): Argument #1 ($message) must be of type string, %s given", + zend_zval_value_name(&message) + ); + } + zval_ptr_dtor(&message); +} + +ZEND_API ZEND_COLD zend_result ZEND_FASTCALL zend_attribute_get_nonpublic_suffix(HashTable *attributes, zend_string **message_suffix) +{ + *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (!attributes) { + return SUCCESS; + } + + zend_attribute *nonpublicConstructor = zend_get_attribute_str( + attributes, + "nonpublicconstructor", + sizeof("nonpublicconstructor")-1 + ); + + if (!nonpublicConstructor) { + return SUCCESS; + } + + ZEND_ASSERT(nonpublicConstructor->argc == 1); + + zend_result result = FAILURE; + zend_string *message_prop = ZSTR_EMPTY_ALLOC(); + + zval obj; + ZVAL_UNDEF(&obj); + zval *z; + + /* Construct the NonpublicConstructor object to correctly handle parameter processing. */ + if (FAILURE == zend_get_attribute_object( + &obj, + zend_ce_nonpublic_constructor, + nonpublicConstructor, + NULL, + NULL + )) { + goto out; + } + + /* Extract the $message property. */ + z = zend_read_property_ex(zend_ce_nonpublic_constructor, Z_OBJ_P(&obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), false, NULL); + ZEND_ASSERT(z != &EG(uninitialized_zval)); + ZEND_ASSERT(Z_TYPE_P(z) == IS_STRING); + message_prop = zend_string_copy(Z_STR_P(z)); + + /* Construct the suffix. */ + *message_suffix = zend_strpprintf_unchecked( + 0, + ", %S,", + message_prop + ); + + result = SUCCESS; + + out: + + zend_string_release(message_prop); + zval_ptr_dtor(&obj); + + return result; +} + ZEND_METHOD(Attribute, __construct) { zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL; @@ -193,6 +298,30 @@ ZEND_METHOD(Deprecated, __construct) } } +ZEND_METHOD(NonpublicConstructor, __construct) +{ + zend_string *message = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(message) + ZEND_PARSE_PARAMETERS_END(); + + zval messageValue; + ZVAL_STR(&messageValue, message); + + zend_update_property_ex( + zend_ce_nonpublic_constructor, + Z_OBJ_P(ZEND_THIS), + ZSTR_KNOWN(ZEND_STR_MESSAGE), + &messageValue + ); + + /* The assignment might fail due to 'readonly'. */ + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } +} + static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) { if (attributes) { @@ -520,6 +649,10 @@ void zend_register_attribute_ce(void) zend_ce_deprecated = register_class_Deprecated(); attr = zend_mark_internal_attribute(zend_ce_deprecated); + + zend_ce_nonpublic_constructor = register_class_NonpublicConstructor(); + attr = zend_mark_internal_attribute(zend_ce_nonpublic_constructor); + attr->validator = validate_nonpublic_constructor; } void zend_attributes_shutdown(void) diff --git a/Zend/zend_attributes.h b/Zend/zend_attributes.h index 8a825247c00f8..0f817e1253680 100644 --- a/Zend/zend_attributes.h +++ b/Zend/zend_attributes.h @@ -47,6 +47,7 @@ extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter; extern ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value; extern ZEND_API zend_class_entry *zend_ce_override; extern ZEND_API zend_class_entry *zend_ce_deprecated; +extern ZEND_API zend_class_entry *zend_ce_nonpublic_constructor; typedef struct { zend_string *name; @@ -92,6 +93,8 @@ ZEND_API zend_attribute *zend_add_attribute( uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope); +ZEND_API ZEND_COLD zend_result ZEND_FASTCALL zend_attribute_get_nonpublic_suffix(HashTable *attributes, zend_string **message_suffix); + END_EXTERN_C() static zend_always_inline zend_attribute *zend_add_class_attribute(zend_class_entry *ce, zend_string *name, uint32_t argc) diff --git a/Zend/zend_attributes.stub.php b/Zend/zend_attributes.stub.php index 0a35b0c57cb44..a7f9020c7c553 100644 --- a/Zend/zend_attributes.stub.php +++ b/Zend/zend_attributes.stub.php @@ -84,3 +84,14 @@ final class Deprecated public function __construct(?string $message = null, ?string $since = null) {} } + +/** + * @strict-properties + */ +#[Attribute(Attribute::TARGET_METHOD)] +final class NonpublicConstructor +{ + public readonly string $message; + + public function __construct(string $message) {} +} diff --git a/Zend/zend_attributes_arginfo.h b/Zend/zend_attributes_arginfo.h index 018caa47d0ac5..8c27f593bb5ea 100644 --- a/Zend/zend_attributes_arginfo.h +++ b/Zend/zend_attributes_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2358a0d820edd06a1702c84104bfd545af08311c */ + * Stub hash: 9d32931d7b2781cdc520ebfa4538f0b19a51097a */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") @@ -29,6 +29,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Deprecated___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, since, IS_STRING, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NonpublicConstructor___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_METHOD(Attribute, __construct); ZEND_METHOD(ReturnTypeWillChange, __construct); ZEND_METHOD(AllowDynamicProperties, __construct); @@ -38,6 +42,7 @@ ZEND_METHOD(SensitiveParameterValue, getValue); ZEND_METHOD(SensitiveParameterValue, __debugInfo); ZEND_METHOD(Override, __construct); ZEND_METHOD(Deprecated, __construct); +ZEND_METHOD(NonpublicConstructor, __construct); static const zend_function_entry class_Attribute_methods[] = { ZEND_ME(Attribute, __construct, arginfo_class_Attribute___construct, ZEND_ACC_PUBLIC) @@ -76,6 +81,11 @@ static const zend_function_entry class_Deprecated_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_NonpublicConstructor_methods[] = { + ZEND_ME(NonpublicConstructor, __construct, arginfo_class_NonpublicConstructor___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static zend_class_entry *register_class_Attribute(void) { zend_class_entry ce, *class_entry; @@ -253,3 +263,24 @@ static zend_class_entry *register_class_Deprecated(void) return class_entry; } + +static zend_class_entry *register_class_NonpublicConstructor(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "NonpublicConstructor", class_NonpublicConstructor_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES); + + zval property_message_default_value; + ZVAL_UNDEF(&property_message_default_value); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &property_message_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + + zend_string *attribute_name_Attribute_class_NonpublicConstructor_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_NonpublicConstructor_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_NonpublicConstructor_0, 1); + zend_string_release(attribute_name_Attribute_class_NonpublicConstructor_0); + zval attribute_Attribute_class_NonpublicConstructor_0_arg0; + ZVAL_LONG(&attribute_Attribute_class_NonpublicConstructor_0_arg0, ZEND_ATTRIBUTE_TARGET_METHOD); + ZVAL_COPY_VALUE(&attribute_Attribute_class_NonpublicConstructor_0->args[0].value, &attribute_Attribute_class_NonpublicConstructor_0_arg0); + + return class_entry; +} diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index a6ea91a7425b9..7cbe731e01cf6 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -24,6 +24,7 @@ #include "zend_exceptions.h" #include "zend_generators.h" #include "zend_closures.h" +#include "zend_attributes.h" #include "zend_generators_arginfo.h" #include "zend_observer.h" #include "zend_vm_opcodes.h" @@ -471,14 +472,6 @@ static zend_object *zend_generator_create(zend_class_entry *class_type) /* {{{ * } /* }}} */ -static ZEND_COLD zend_function *zend_generator_get_constructor(zend_object *object) /* {{{ */ -{ - zend_throw_error(NULL, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated"); - - return NULL; -} -/* }}} */ - ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_data *ptr) { if (!ptr->func && Z_TYPE(ptr->This) == IS_OBJECT) { @@ -891,6 +884,13 @@ static inline void zend_generator_rewind(zend_generator *generator) /* {{{ */ } /* }}} */ +ZEND_METHOD(Generator, __construct) +{ + // Reachable via reflection + zend_throw_error(NULL, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated"); + RETURN_THROWS(); +} + /* {{{ Rewind the generator */ ZEND_METHOD(Generator, rewind) { @@ -1221,7 +1221,6 @@ void zend_register_generator_ce(void) /* {{{ */ zend_generator_handlers.dtor_obj = zend_generator_dtor_storage; zend_generator_handlers.get_gc = zend_generator_get_gc; zend_generator_handlers.clone_obj = NULL; - zend_generator_handlers.get_constructor = zend_generator_get_constructor; zend_ce_ClosedGeneratorException = register_class_ClosedGeneratorException(zend_ce_exception); } diff --git a/Zend/zend_generators.stub.php b/Zend/zend_generators.stub.php index c081d8e35e26d..428a6360dfa32 100644 --- a/Zend/zend_generators.stub.php +++ b/Zend/zend_generators.stub.php @@ -8,6 +8,9 @@ */ final class Generator implements Iterator { + #[\NonpublicConstructor("the \"Generator\" class is reserved for internal use and cannot be manually instantiated")] + private function __construct() {} + public function rewind(): void {} public function valid(): bool {} diff --git a/Zend/zend_generators_arginfo.h b/Zend/zend_generators_arginfo.h index 54a6744af1b64..5519afc408027 100644 --- a/Zend/zend_generators_arginfo.h +++ b/Zend/zend_generators_arginfo.h @@ -1,5 +1,8 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: d376e984db0db6ccd9356f632f9d7e1382b2afb7 */ + * Stub hash: f15f37a5f93befeddb75e34c89bc0d84879a511b */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Generator___construct, 0, 0, 0) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Generator_rewind, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -27,6 +30,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Generator___debugInfo, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() +ZEND_METHOD(Generator, __construct); ZEND_METHOD(Generator, rewind); ZEND_METHOD(Generator, valid); ZEND_METHOD(Generator, current); @@ -38,6 +42,7 @@ ZEND_METHOD(Generator, getReturn); ZEND_METHOD(Generator, __debugInfo); static const zend_function_entry class_Generator_methods[] = { + ZEND_ME(Generator, __construct, arginfo_class_Generator___construct, ZEND_ACC_PRIVATE) ZEND_ME(Generator, rewind, arginfo_class_Generator_rewind, ZEND_ACC_PUBLIC) ZEND_ME(Generator, valid, arginfo_class_Generator_valid, ZEND_ACC_PUBLIC) ZEND_ME(Generator, current, arginfo_class_Generator_current, ZEND_ACC_PUBLIC) @@ -58,6 +63,15 @@ static zend_class_entry *register_class_Generator(zend_class_entry *class_entry_ class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); zend_class_implements(class_entry, 1, class_entry_Iterator); + + zend_string *attribute_name_NonpublicConstructor_func___construct_0 = zend_string_init_interned("NonpublicConstructor", sizeof("NonpublicConstructor") - 1, 1); + zend_attribute *attribute_NonpublicConstructor_func___construct_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "__construct", sizeof("__construct") - 1), attribute_name_NonpublicConstructor_func___construct_0, 1); + zend_string_release(attribute_name_NonpublicConstructor_func___construct_0); + zval attribute_NonpublicConstructor_func___construct_0_arg0; + zend_string *attribute_NonpublicConstructor_func___construct_0_arg0_str = zend_string_init("the \"Generator\" class is reserved for internal use and cannot be manually instantiated", strlen("the \"Generator\" class is reserved for internal use and cannot be manually instantiated"), 1); + ZVAL_STR(&attribute_NonpublicConstructor_func___construct_0_arg0, attribute_NonpublicConstructor_func___construct_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_NonpublicConstructor_func___construct_0->args[0].value, &attribute_NonpublicConstructor_func___construct_0_arg0); + return class_entry; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index cdcdd1622746f..5e300a2890ad1 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -19,6 +19,7 @@ */ #include "zend.h" +#include "zend_attributes.h" #include "zend_globals.h" #include "zend_lazy_objects.h" #include "zend_variables.h" @@ -2024,14 +2025,29 @@ ZEND_API ZEND_COLD bool zend_std_unset_static_property(zend_class_entry *ce, zen static ZEND_COLD zend_never_inline void zend_bad_constructor_call(zend_function *constructor, zend_class_entry *scope) /* {{{ */ { + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(constructor->common.attributes, &message_suffix) == FAILURE) { + return; + } + if (scope) { - zend_throw_error(NULL, "Call to %s %s::%s() from scope %s", + zend_throw_error(NULL, "Call to %s %s::%s() from scope %s%S", zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name), - ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name) + ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name), + message_suffix ); } else { - zend_throw_error(NULL, "Call to %s %s::%s() from global scope", zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name)); + zend_throw_error( + NULL, + "Call to %s %s::%s() from global scope%S", + zend_visibility_string(constructor->common.fn_flags), + ZSTR_VAL(constructor->common.scope->name), + ZSTR_VAL(constructor->common.function_name), + message_suffix + ); } + zend_string_release(message_suffix); } /* }}} */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7e471b5acd8b6..f1ddc6f13eaf5 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3783,7 +3783,19 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9209399a5cdbf..114d95ebffdfc 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7369,7 +7369,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -9943,7 +9955,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -10701,7 +10725,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -12435,7 +12471,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -25471,7 +25519,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -28404,7 +28464,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -29914,7 +29986,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -32853,7 +32937,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -35124,7 +35220,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -37293,7 +37401,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -37704,7 +37824,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; @@ -39938,7 +40070,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U HANDLE_EXCEPTION(); } if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix(ce->constructor->common.attributes, &message_suffix) == FAILURE) { + ZEND_ASSERT(EG(exception)); + } else { + zend_throw_error( + NULL, + "Cannot call private %s::__construct()%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); + } HANDLE_EXCEPTION(); } fbc = ce->constructor; From ea6d44782f7a6ddae0bd842d8b2953e1c9029c39 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 17 Feb 2025 19:35:49 -0800 Subject: [PATCH 2/4] Other tests exist too --- Zend/tests/generators/errors/generator_instantiate_error.phpt | 2 +- ext/reflection/tests/bug64007.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/tests/generators/errors/generator_instantiate_error.phpt b/Zend/tests/generators/errors/generator_instantiate_error.phpt index 7e55fe357db34..03be10c2daf4a 100644 --- a/Zend/tests/generators/errors/generator_instantiate_error.phpt +++ b/Zend/tests/generators/errors/generator_instantiate_error.phpt @@ -7,7 +7,7 @@ new Generator; ?> --EXPECTF-- -Fatal error: Uncaught Error: The "Generator" class is reserved for internal use and cannot be manually instantiated in %s:%d +Fatal error: Uncaught Error: Call to private Generator::__construct() from global scope, the "Generator" class is reserved for internal use and cannot be manually instantiated, in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/ext/reflection/tests/bug64007.phpt b/ext/reflection/tests/bug64007.phpt index a25beb6360d72..199cca6e390b5 100644 --- a/ext/reflection/tests/bug64007.phpt +++ b/ext/reflection/tests/bug64007.phpt @@ -16,7 +16,7 @@ var_dump($generator); --EXPECTF-- string(%d) "Class Generator is an internal class marked as final that cannot be instantiated without invoking its constructor" -Fatal error: Uncaught Error: The "Generator" class is reserved for internal use and cannot be manually instantiated in %sbug64007.php:%d +Fatal error: Uncaught ReflectionException: Access to non-public constructor of class Generator in %sbug64007.php:%d Stack trace: #0 %s(%d): ReflectionClass->newInstance() #1 {main} From 87c96077a28bd177da54d91676ecf05e2f50d698 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 17 Feb 2025 19:47:30 -0800 Subject: [PATCH 3/4] Reflection integration --- .../Reflection_newInstance.phpt | 20 ++++++++++ .../Reflection_newInstanceArgs.phpt | 20 ++++++++++ ext/reflection/php_reflection.c | 40 ++++++++++++++++++- ext/reflection/tests/bug64007.phpt | 2 +- 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/attributes/NonpublicConstructor/Reflection_newInstance.phpt create mode 100644 Zend/tests/attributes/NonpublicConstructor/Reflection_newInstanceArgs.phpt diff --git a/Zend/tests/attributes/NonpublicConstructor/Reflection_newInstance.phpt b/Zend/tests/attributes/NonpublicConstructor/Reflection_newInstance.phpt new file mode 100644 index 0000000000000..f251e5116e072 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/Reflection_newInstance.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\NonpublicConstructor]: affects message from ReflectionClass::newInstance() +--FILE-- +newInstance( true ); + +?> +--EXPECTF-- +Fatal error: Uncaught ReflectionException: Access to non-public constructor of class Demo, use ::getInstance() instead, in %s:%d +Stack trace: +#0 %s(%d): ReflectionClass->newInstance(true) +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/NonpublicConstructor/Reflection_newInstanceArgs.phpt b/Zend/tests/attributes/NonpublicConstructor/Reflection_newInstanceArgs.phpt new file mode 100644 index 0000000000000..9724d90f9f134 --- /dev/null +++ b/Zend/tests/attributes/NonpublicConstructor/Reflection_newInstanceArgs.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\NonpublicConstructor]: affects message from ReflectionClass::newInstanceArgs() +--FILE-- +newInstanceArgs( [ true ] ); + +?> +--EXPECTF-- +Fatal error: Uncaught ReflectionException: Access to non-public constructor of class Demo, use ::getInstance() instead, in %s:%d +Stack trace: +#0 %s(%d): ReflectionClass->newInstanceArgs(Array) +#1 {main} + thrown in %s on line %d diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 6d5b9d71c27ae..3655bec959cae 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4938,7 +4938,25 @@ ZEND_METHOD(ReflectionClass, newInstance) HashTable *named_params; if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix( + constructor->common.attributes, + &message_suffix) == FAILURE + ) { + ZEND_ASSERT(EG(exception)); + zval_ptr_dtor(return_value); + RETURN_THROWS(); + } + + zend_throw_exception_ex( + reflection_exception_ptr, + 0, + "Access to non-public constructor of class %s%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); zval_ptr_dtor(return_value); RETURN_NULL(); } @@ -5011,7 +5029,25 @@ ZEND_METHOD(ReflectionClass, newInstanceArgs) /* Run the constructor if there is one */ if (constructor) { if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name)); + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (zend_attribute_get_nonpublic_suffix( + constructor->common.attributes, + &message_suffix) == FAILURE + ) { + ZEND_ASSERT(EG(exception)); + zval_ptr_dtor(return_value); + RETURN_THROWS(); + } + + zend_throw_exception_ex( + reflection_exception_ptr, + 0, + "Access to non-public constructor of class %s%S", + ZSTR_VAL(ce->name), + message_suffix + ); + zend_string_release(message_suffix); zval_ptr_dtor(return_value); RETURN_NULL(); } diff --git a/ext/reflection/tests/bug64007.phpt b/ext/reflection/tests/bug64007.phpt index 199cca6e390b5..5dc6ff95fc083 100644 --- a/ext/reflection/tests/bug64007.phpt +++ b/ext/reflection/tests/bug64007.phpt @@ -16,7 +16,7 @@ var_dump($generator); --EXPECTF-- string(%d) "Class Generator is an internal class marked as final that cannot be instantiated without invoking its constructor" -Fatal error: Uncaught ReflectionException: Access to non-public constructor of class Generator in %sbug64007.php:%d +Fatal error: Uncaught ReflectionException: Access to non-public constructor of class Generator, the "Generator" class is reserved for internal use and cannot be manually instantiated, in %sbug64007.php:%d Stack trace: #0 %s(%d): ReflectionClass->newInstance() #1 {main} From 5982e422a7b09210337b1ec67ba8986e3f2395cd Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 17 Feb 2025 21:18:45 -0800 Subject: [PATCH 4/4] Percentage --- Zend/zend_object_handlers.c | 8 +++--- Zend/zend_vm_def.h | 4 +-- Zend/zend_vm_execute.h | 48 ++++++++++++++++----------------- ext/reflection/php_reflection.c | 8 +++--- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 5e300a2890ad1..c932db7788fa9 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -2032,19 +2032,19 @@ static ZEND_COLD zend_never_inline void zend_bad_constructor_call(zend_function } if (scope) { - zend_throw_error(NULL, "Call to %s %s::%s() from scope %s%S", + zend_throw_error(NULL, "Call to %s %s::%s() from scope %s%s", zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name), - message_suffix + ZSTR_VAL(message_suffix) ); } else { zend_throw_error( NULL, - "Call to %s %s::%s() from global scope%S", + "Call to %s %s::%s() from global scope%s", zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), - message_suffix + ZSTR_VAL(message_suffix) ); } zend_string_release(message_suffix); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f1ddc6f13eaf5..6b7147e7f1029 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3790,9 +3790,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 114d95ebffdfc..12827535da90f 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7376,9 +7376,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -9962,9 +9962,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -10732,9 +10732,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -12478,9 +12478,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -25526,9 +25526,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -28471,9 +28471,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -29993,9 +29993,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -32944,9 +32944,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -35227,9 +35227,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -37408,9 +37408,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -37831,9 +37831,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } @@ -40077,9 +40077,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } else { zend_throw_error( NULL, - "Cannot call private %s::__construct()%S", + "Cannot call private %s::__construct()%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 3655bec959cae..3bcbbe8c8de31 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4952,9 +4952,9 @@ ZEND_METHOD(ReflectionClass, newInstance) zend_throw_exception_ex( reflection_exception_ptr, 0, - "Access to non-public constructor of class %s%S", + "Access to non-public constructor of class %s%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); zval_ptr_dtor(return_value); @@ -5043,9 +5043,9 @@ ZEND_METHOD(ReflectionClass, newInstanceArgs) zend_throw_exception_ex( reflection_exception_ptr, 0, - "Access to non-public constructor of class %s%S", + "Access to non-public constructor of class %s%s", ZSTR_VAL(ce->name), - message_suffix + ZSTR_VAL(message_suffix) ); zend_string_release(message_suffix); zval_ptr_dtor(return_value);