From fe60ed96c03e36cac5291dbd8f51435d379cbbc3 Mon Sep 17 00:00:00 2001 From: twosee Date: Thu, 15 Apr 2021 11:40:34 +0800 Subject: [PATCH] Fixed bug #80929 The function name should be kept if Closure was created from the function which is marked as ZEND_ACC_CALL_VIA_TRAMPOLINE, because it is not a one-time thing and it may be called multiple times. --- Zend/tests/closures/bug80929.phpt | 56 +++++++++++++++++++++++++++++++ Zend/zend_closures.c | 3 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/closures/bug80929.phpt diff --git a/Zend/tests/closures/bug80929.phpt b/Zend/tests/closures/bug80929.phpt new file mode 100644 index 0000000000000..43e53a6ad0795 --- /dev/null +++ b/Zend/tests/closures/bug80929.phpt @@ -0,0 +1,56 @@ +--TEST-- +Bug #80929: Method name corruption related to zend_closure_call_magic +--FILE-- +subscribedEvents = $subscribedEvents; + $this->subscriber = $subscriber; + foreach ($this->subscribedEvents as $eventName => $params) { + $this->listener = Closure::fromCallable([$this, $params]); + } + } + + public function __call(string $name, array $arguments) + { + return $this->subscriber->$name(...$arguments); + } + + public function dispatch($event, string $eventName) + { + ($this->listener)($event, $eventName, null); + } +} + +$proxy = new SubscriberProxy( + ['defaultEvent' => 'handleDefaultEvent'], + new DefaultListener() +); + +for ($i = 0; $i < 10; $i++) { + echo $i . PHP_EOL; + $proxy->dispatch(null, 'defaultEvent'); +} +?> +--EXPECT-- +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index f60d83e256aac..e0e820b6a8d25 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -270,7 +270,6 @@ static ZEND_NAMED_FUNCTION(zend_closure_call_magic) /* {{{ */ { zend_call_function(&fci, &fcc); - zval_ptr_dtor(&fci.params[0]); zval_ptr_dtor(&fci.params[1]); } /* }}} */ @@ -473,6 +472,8 @@ static void zend_closure_free_storage(zend_object *object) /* {{{ */ if (closure->func.type == ZEND_USER_FUNCTION) { destroy_op_array(&closure->func.op_array); + } else if (closure->orig_internal_handler == zend_closure_call_magic) { + zend_string_release(closure->func.common.function_name); } if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {