[PHP-CVS] [php-src] master: Fix double-free of closure run_time_cache in partial application (#22790)

[email protected] (Ilia Alshanetsky via GitHub)
Newsgroups php.cvs
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Committer: GitHub (web-flow)
Pusher: iliaal
Date: 2026-07-17T13:22:39-04:00

Commit: https://github.com/php/php-src/commit/c191020fdaf020e63b9e9afcb225ce3481b48abb
Raw diff: https://github.com/php/php-src/commit/c191020fdaf020e63b9e9afcb225ce3481b48abb.diff

Fix double-free of closure run_time_cache in partial application (#22790)

A partial over a closure whose op_array is not persistent shallow-copies
the closure's op_array into the per-request PFA cache as a lifetime
anchor. The copy inherited ZEND_ACC_HEAP_RT_CACHE and the run_time_cache
pointer, so destroy_op_array() freed the closure's cache twice: once when
the closure was released and again at PFA cache teardown. Use
function_add_ref() for the copy, which resets the per-request
run_time_cache and static_variables_ptr map pointers, so only the live
closure owns and frees the cache.

Changed paths:
  A  Zend/tests/partial_application/closure_rt_cache_lifetime.phpt
  M  ext/opcache/ZendAccelerator.c


Diff:

diff --git a/Zend/tests/partial_application/closure_rt_cache_lifetime.phpt b/Zend/tests/partial_application/closure_rt_cache_lifetime.phpt
new file mode 100644
index 000000000000..7eb4810cf00a
--- /dev/null
+++ b/Zend/tests/partial_application/closure_rt_cache_lifetime.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Partial application over a Closure::fromCallable() must not double-free the run_time_cache
+--FILE--
+<?php
+class C {
+    public function m($x, $y) { return $x + $y; }
+}
+
+$cl = Closure::fromCallable([new C, 'm']);
+$partial = $cl(10, ?);
+var_dump($partial(5));
+unset($partial);
+unset($cl);
+gc_collect_cycles();
+echo "OK\n";
+?>
+--EXPECT--
+int(15)
+OK
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 2c467dc1fc8a..0a7a62eae9a9 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -2146,8 +2146,7 @@ zend_op_array *zend_accel_compile_pfa(zend_ast *ast,
 			 * See comment in zend_accel_pfa_key(). */
 			zend_op_array *copy = zend_arena_alloc(&CG(arena), sizeof(*copy));
 			memcpy(copy, called_function, sizeof(*copy));
-			zend_string_addref(copy->function_name);
-			(*copy->refcount)++;
+			function_add_ref((zend_function *) copy);
 			/* Reference the copy in op_array->dynamic_func_defs so that it's
 			 * destroyed when op_array is destroyed. */
 			ZEND_ASSERT(!op_array->dynamic_func_defs && !op_array->num_dynamic_func_defs);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.