[php-src] master: PFA: Extend local pointer map after loading PFA from SHM (#23250)

Arnaud Le Blanc via GitHub <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Arnaud Le Blanc (arnaud-lb)
Committer: GitHub (web-flow)
Pusher: arnaud-lb
Date: 2026-08-25T10:20:32+02:00

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

PFA: Extend local pointer map after loading PFA from SHM (#23250)

When loading a PFA from SHM we may need to extend the local pointer map because
the PFA may use pointers higher than CG(map_ptr_last). Similar synchronization
happens in inheritance cache or when loading whole scripts.

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


Diff:

diff --git a/Zend/tests/partial_application/map_ptr_last.phpt b/Zend/tests/partial_application/map_ptr_last.phpt
new file mode 100644
index 000000000000..1ee70d457358
--- /dev/null
+++ b/Zend/tests/partial_application/map_ptr_last.phpt
@@ -0,0 +1,58 @@
+--TEST--
+PFA and ZCSG(map_ptr_last)
+--CREDITS--
+Ryan @ Calif.io
+--EXTENSIONS--
+pcntl
+--INI--
+opcache.file_update_protection=0
+--SKIPIF--
+<?php
+if (!function_exists('pcntl_fork')) {
+    die("skip no pcntl_fork");
+}
+?>
+--FILE--
+<?php
+
+function f($a, $b) {
+    return new ReflectionClass($a);
+}
+
+function get_pfa() {
+    return f(?, 0);
+}
+
+$pid = pcntl_fork();
+if ($pid) {
+    pcntl_waitpid($pid, $status, 0);
+
+    /* PFA retrieved from SHM, run_time_cache > CG(map_ptr_last) */
+    var_dump(get_pfa()('ReflectionClass'));
+} else {
+    /* Increment ZSCG(map_ptr_last) enough to mandate a realloc in other processes.
+     * We do so by compiling many functions that are guaranteed to allocate a map_ptr. */
+
+    $fd = fopen(__DIR__ . '/map_ptr_last.inc', 'w');
+    fwrite($fd, "<?php\n");
+    for ($i = 0; $i < 4096; $i++) {
+        fprintf($fd, "function pfa_map_ptr_flood_%05d(\$obj) { return \$obj->prop; }\n", $i);
+    }
+    fclose($fd);
+
+    require __DIR__ . '/map_ptr_last.inc';
+
+    /* Compile a PFA */
+    get_pfa()('ReflectionClass');
+}
+
+?>
+--CLEAN--
+<?php
+@unlink(__DIR__ . '/map_ptr_last.inc');
+?>
+--EXPECTF--
+object(ReflectionClass)#%d (1) {
+  ["name"]=>
+  string(15) "ReflectionClass"
+}
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index f4bdcf3e7f7a..05fb6700ea72 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -2073,6 +2073,9 @@ const zend_op_array *zend_accel_pfa_cache_get(
 				zend_emit_recorded_errors_ex(persistent_script->num_warnings,
 						persistent_script->warnings);
 			}
+			if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
+				zend_map_ptr_extend(ZCSG(map_ptr_last));
+			}
 		}
 	} else {
 		op_array = zend_hash_find_ptr(&EG(partial_function_application_cache), key);
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.