From 76b99df2bbad5eeb2205e66441ee4157b8238eb3 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 11 Nov 2025 16:13:56 +0100 Subject: [PATCH] Correctly handle extra named args for magic call in debug_backtrace_get_args() --- Zend/tests/function_arguments/gh20435_2.phpt | 38 ++++++++++++++++++++ Zend/zend_builtin_functions.c | 8 +++-- 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/function_arguments/gh20435_2.phpt diff --git a/Zend/tests/function_arguments/gh20435_2.phpt b/Zend/tests/function_arguments/gh20435_2.phpt new file mode 100644 index 0000000000000..a58c4d6be1ca5 --- /dev/null +++ b/Zend/tests/function_arguments/gh20435_2.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-20435: ZEND_CALL_HAS_EXTRA_NAMED_PARAMS & magic methods in debug_backtrace_get_args() +--FILE-- +__toString(), "\n\n"; + } + public function __call($name, $args) { + echo (new Exception())->__toString(), "\n\n"; + } + public function __invoke(...$args) { + echo (new Exception())->__toString(), "\n"; + } +} + +$c = new C(); +$c->foo(bar: 'bar'); +C::foo(bar: 'bar'); +$c(bar: 'bar'); + +?> +--EXPECTF-- +Exception in %s:%d +Stack trace: +#0 %s(%d): C->__call('foo', Array) +#1 {main} + +Exception in %s:%d +Stack trace: +#0 %s(%d): C::__callStatic('foo', Array) +#1 {main} + +Exception in %s:%d +Stack trace: +#0 %s(%d): C->__invoke(bar: 'bar') +#1 {main} diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 344983a6e2878..374d4b3734eaa 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1680,12 +1680,14 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / ZVAL_EMPTY_ARRAY(arg_array); } - if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + if ((ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) + /* __call and __callStatic are non-variadic, potentially with + * HAS_EXTRA_NAMED_PARAMS set. Don't add extra args, as they're already + * contained in the 2nd param. */ + && (call->func->common.fn_flags & ZEND_ACC_VARIADIC)) { zend_string *name; zval *arg; - ZEND_ASSERT(call->func->common.fn_flags & ZEND_ACC_VARIADIC); - zend_attribute *attribute = zend_get_parameter_attribute_str( call->func->common.attributes, "sensitiveparameter",