mirror of
https://github.com/php/php-src.git
synced 2026-10-28 17:56:50 +08:00
Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5: Fix GH-24438: Preserve indirect types in JIT side traces Fix GH-17733: System entropy does not take into account function order, resulting in wrong functions possibly called in different configurations
This commit is contained in:
7 files changed
+171
-23
No files matched your search
@@ -32,6 +32,10 @@ PHP NEWS
|
||||
assigning to a reference). (waroad)
|
||||
. Fixed bug GH-24745 (File cache loses attributes on constants on 32-bit
|
||||
builds). (Yannick Decat, Lazizbek Ergashev)
|
||||
. Fixed bug GH-17733 (System entropy does not take into account function
|
||||
order, resulting in wrong functions possibly called
|
||||
in different configurations). (ndossche)
|
||||
. Fixed bug GH-24438 (Preserve indirect types in JIT side traces). (aasul)
|
||||
|
||||
- OpenSSL:
|
||||
. Fixed build with OpenSSL 4.1. (Weilin Du)
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "zend_enum.h"
|
||||
#include "zend_object_handlers.h"
|
||||
#include "zend_observer.h"
|
||||
#include "zend_system_id.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -3236,7 +3235,6 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
|
||||
}
|
||||
zend_flf_handlers[zend_flf_count] = flf_info->handler;
|
||||
zend_flf_functions[zend_flf_count] = (zend_function *)reg_function;
|
||||
zend_add_system_entropy("frameless", ZSTR_VAL(reg_function->function_name), &flf_info->num_args, sizeof(flf_info->num_args));
|
||||
zend_flf_count++;
|
||||
flf_info++;
|
||||
}
|
||||
|
||||
@@ -87,6 +87,21 @@ void zend_finalize_system_id(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Cached scripts can refer to offsets of internal functions.
|
||||
* Effects of disable_functions and frameless functions must be taken into account.
|
||||
* Therefore, embed the function names in-order.
|
||||
* Updating third party extensions may change function signatures, arginfo, offsets, ...
|
||||
* Therefore, also embed the loaded modules and their versions. */
|
||||
ZEND_HASH_MAP_FOREACH_STR_KEY(CG(function_table), zend_string *name) {
|
||||
PHP_MD5Update(&context, ZSTR_VAL(name), ZSTR_LEN(name) + 1);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, zend_module_entry *mod) {
|
||||
PHP_MD5Update(&context, mod->name, strlen(mod->name) + 1);
|
||||
if (EXPECTED(mod->version != NO_VERSION_YET)) {
|
||||
PHP_MD5Update(&context, mod->version, strlen(mod->version) + 1);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
PHP_MD5Final(digest, &context);
|
||||
zend_bin2hex(zend_system_id, digest, sizeof digest);
|
||||
finalized = 1;
|
||||
|
||||
@@ -1772,7 +1772,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
|
||||
if (i < op_array->last_var) {
|
||||
ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
|
||||
} else {
|
||||
ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
|
||||
ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_INDIRECT | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
|
||||
}
|
||||
}
|
||||
if (i < parent_vars_count) {
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
--TEST--
|
||||
GH-17733 (System entropy does not take into account function order, resulting in wrong functions possibly called in different configurations)
|
||||
--EXTENSIONS--
|
||||
opcache
|
||||
--FILE--
|
||||
<?php
|
||||
$cache = __DIR__ . '/' . 'gh17733';
|
||||
$script = $cache . '/' . 'call.php';
|
||||
mkdir($cache);
|
||||
|
||||
function write_script(string $script, int $version): void {
|
||||
file_put_contents($script, <<<PHP
|
||||
<?php
|
||||
echo "v$version\n";
|
||||
try {
|
||||
var_dump(str_repeat("ab", 3));
|
||||
} catch (\Throwable \$e) {
|
||||
echo \$e::class, ": ", \$e->getMessage(), "\n";
|
||||
}
|
||||
PHP);
|
||||
}
|
||||
|
||||
function run(string $cache, string $script, string $disable_functions): 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 . '/' . $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',
|
||||
'-d', 'opcache.validate_timestamps=0', // Important to tell apart versions
|
||||
'-d', 'disable_functions=' . $disable_functions,
|
||||
$script,
|
||||
);
|
||||
$proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['redirect', 1]], $pipes);
|
||||
echo stream_get_contents($pipes[1]);
|
||||
proc_close($proc);
|
||||
}
|
||||
|
||||
function system_ids(string $cache): int {
|
||||
$pattern = PHP_OS_FAMILY === 'Windows' ? '/*/*' : '/*';
|
||||
return count(glob($cache . $pattern, GLOB_ONLYDIR));
|
||||
}
|
||||
|
||||
write_script($script, 1);
|
||||
run($cache, $script, '');
|
||||
var_dump(system_ids($cache));
|
||||
|
||||
write_script($script, 2);
|
||||
echo "--- Same environment reuses the cache ---\n";
|
||||
run($cache, $script, '');
|
||||
var_dump(system_ids($cache));
|
||||
|
||||
echo "--- Shifted function table ---\n";
|
||||
run($cache, $script, 'zend_version');
|
||||
var_dump(system_ids($cache));
|
||||
|
||||
echo "--- Disabled function ---\n";
|
||||
run($cache, $script, 'str_repeat');
|
||||
var_dump(system_ids($cache));
|
||||
|
||||
write_script($script, 3);
|
||||
echo "--- Each environment reuses its own cache ---\n";
|
||||
run($cache, $script, 'zend_version');
|
||||
run($cache, $script, 'str_repeat');
|
||||
run($cache, $script, '');
|
||||
var_dump(system_ids($cache));
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$cache = __DIR__ . '/' . 'gh17733';
|
||||
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--
|
||||
v1
|
||||
string(6) "ababab"
|
||||
int(1)
|
||||
--- Same environment reuses the cache ---
|
||||
v1
|
||||
string(6) "ababab"
|
||||
int(1)
|
||||
--- Shifted function table ---
|
||||
v2
|
||||
string(6) "ababab"
|
||||
int(2)
|
||||
--- Disabled function ---
|
||||
v2
|
||||
Error: Call to undefined function str_repeat()
|
||||
int(3)
|
||||
--- Each environment reuses its own cache ---
|
||||
v2
|
||||
string(6) "ababab"
|
||||
v2
|
||||
Error: Call to undefined function str_repeat()
|
||||
v1
|
||||
string(6) "ababab"
|
||||
int(3)
|
||||
@@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
GH-24438 (Tracing JIT preserves indirect arguments on side-trace entry)
|
||||
--EXTENSIONS--
|
||||
opcache
|
||||
--INI--
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.file_update_protection=0
|
||||
opcache.jit_buffer_size=64M
|
||||
opcache.jit=tracing
|
||||
opcache.jit_hot_loop=1
|
||||
opcache.jit_hot_func=1
|
||||
opcache.jit_hot_return=1
|
||||
opcache.jit_hot_side_exit=1
|
||||
opcache.jit_max_polymorphic_calls=0
|
||||
--FILE--
|
||||
<?php
|
||||
function byVal($value) {
|
||||
$value = (int) $value + 1000;
|
||||
return $value;
|
||||
}
|
||||
|
||||
function byRef(&$value) {
|
||||
$value = (int) $value + 1;
|
||||
return $value;
|
||||
}
|
||||
|
||||
$fns = ['byVal', 'byRef'];
|
||||
$arr = [10, 20];
|
||||
for ($i = 0; $i < 120; $i++) {
|
||||
$f = $fns[$i % 2];
|
||||
$f($arr[1]);
|
||||
$f($arr[0]);
|
||||
}
|
||||
|
||||
var_dump($arr[0], $arr[1]);
|
||||
?>
|
||||
--EXPECT--
|
||||
int(70)
|
||||
int(80)
|
||||
@@ -583,32 +583,13 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
|
||||
}
|
||||
if (opline->op2_type == IS_CONST) {
|
||||
SERIALIZE_PTR(opline->op2.zv);
|
||||
|
||||
/* See GH-17733. Reset Z_EXTRA_P(op2) of ZEND_INIT_FCALL, which
|
||||
* is an offset into the global function table, to avoid calling
|
||||
* incorrect functions when environment changes. This, and the
|
||||
* equivalent code below, can be removed once proper system ID
|
||||
* validation is implemented. */
|
||||
if (opline->opcode == ZEND_INIT_FCALL) {
|
||||
zval *op2 = opline->op2.zv;
|
||||
UNSERIALIZE_PTR(op2);
|
||||
Z_EXTRA_P(op2) = 0;
|
||||
ZEND_VM_SET_OPCODE_HANDLER(opline);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (opline->op1_type == IS_CONST) {
|
||||
opline->op1.constant = RT_CONSTANT(opline, opline->op1) - literals;
|
||||
}
|
||||
if (opline->op2_type == IS_CONST) {
|
||||
zval *op2 = RT_CONSTANT(opline, opline->op2);
|
||||
opline->op2.constant = op2 - literals;
|
||||
|
||||
/* See GH-17733 and comment above. */
|
||||
if (opline->opcode == ZEND_INIT_FCALL) {
|
||||
Z_EXTRA_P(op2) = 0;
|
||||
ZEND_VM_SET_OPCODE_HANDLER(opline);
|
||||
}
|
||||
opline->op2.constant = RT_CONSTANT(opline, opline->op2) - literals;
|
||||
}
|
||||
#endif
|
||||
#if ZEND_USE_ABS_JMP_ADDR
|
||||
|
||||
Reference in new issue
Block a user