Files
php-src/ext/opcache/tests/file_cache_frameless_handler.phpt
Ilia Alshanetsky 1bffb94a2f Zend: Include frameless functions in the system id
FRAMELESS_ICALL stores an index into zend_flf_handlers, whose layout
depends on the loaded extensions, but zend_system_id did not cover it. A
file cache warmed with a frameless-declaring extension then crashed in a
process without it, or one that loads it with dl(), which registers no
frameless handlers. Each persistent frameless function now adds its name
and arity to the system id when it registers, before disable_functions can
free the function record.

Closes GH-24047
2026-10-02 16:17:03 -04:00

82 lines
2.3 KiB
PHP

--TEST--
opcache file cache must not reuse frameless function indices across extension sets
--EXTENSIONS--
opcache
--SKIPIF--
<?php
$dl_test = PHP_OS_FAMILY === 'Windows' ? 'php_dl_test.dll' : 'dl_test.so';
if (!file_exists(ini_get('extension_dir') . DIRECTORY_SEPARATOR . $dl_test)) {
die('skip dl_test extension is not built');
}
?>
--FILE--
<?php
$cache = __DIR__ . DIRECTORY_SEPARATOR . 'file_cache_frameless_handler';
$script = $cache . DIRECTORY_SEPARATOR . 'call.php';
mkdir($cache);
file_put_contents($script, <<<'PHP'
<?php
if (isset($argv[1])) {
dl('dl_test');
}
try {
var_dump(dl_test_frameless(7));
} catch (Error $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
PHP);
function run(string $cache, array $args): void {
$ext = ini_get('extension_dir');
$opcache = PHP_OS_FAMILY === 'Windows' ? 'php_opcache.dll' : 'opcache.so';
$cmd = [PHP_BINARY, '-n', '-d', 'extension_dir="' . $ext . '"'];
if (file_exists($ext . DIRECTORY_SEPARATOR . $opcache)) {
array_push($cmd, '-d', 'zend_extension=opcache');
}
array_push($cmd,
'-d', 'opcache.enable_cli=1',
'-d', 'opcache.file_cache="' . $cache . '"',
'-d', 'opcache.file_cache_only=1',
'-d', 'opcache.file_update_protection=0',
...$args,
);
$proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
echo stream_get_contents($pipes[1]);
stream_get_contents($pipes[2]);
proc_close($proc);
}
function system_ids(string $cache): int {
$pattern = PHP_OS_FAMILY === 'Windows' ? '/*/*' : '/*';
return count(glob($cache . $pattern, GLOB_ONLYDIR));
}
run($cache, ['-d', 'extension=dl_test', $script]);
var_dump(system_ids($cache));
run($cache, [$script, 'dl']);
var_dump(system_ids($cache));
run($cache, [$script]);
var_dump(system_ids($cache));
?>
--CLEAN--
<?php
$cache = __DIR__ . DIRECTORY_SEPARATOR . 'file_cache_frameless_handler';
if (is_dir($cache)) {
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($cache, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($it as $file) {
$file->isDir() ? rmdir($file->getPathname()) : unlink($file->getPathname());
}
rmdir($cache);
}
?>
--EXPECT--
int(7)
int(1)
int(7)
int(2)
Error: Call to undefined function dl_test_frameless()
int(2)