mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix GH-17307: Internal closure causes JIT failure
`bcadd(...)` is a closure for an internal function, and `zend_jit_push_call_frame` takes into account both last_var and the difference in argument numbers not only for user code but also for internal code. However, this is inconsistent with `zend_vm_calc_used_stack`, causing argument corruption. Making this consistent fixes the issue. I could only reproduce the assertion failure when using Valgrind. Closes GH-17319.
This commit is contained in:
parent
c790c5b2e7
commit
28b448ac20
3 changed files with 41 additions and 14 deletions
1
NEWS
1
NEWS
|
@ -39,6 +39,7 @@ PHP NEWS
|
|||
- Opcache:
|
||||
. Fixed bug GH-15981 (Segfault with frameless jumps and minimal JIT).
|
||||
(nielsdos)
|
||||
. Fixed bug GH-17307 (Internal closure causes JIT failure). (nielsdos)
|
||||
|
||||
- PHPDBG:
|
||||
. Fix crashes in function registration + test. (nielsdos, Girgias)
|
||||
|
|
|
@ -8503,18 +8503,16 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
|
|||
} else {
|
||||
ir_ref num_args_ref;
|
||||
ir_ref if_internal_func = IR_UNUSED;
|
||||
const size_t func_type_offset = is_closure ? offsetof(zend_closure, func.type) : offsetof(zend_function, type);
|
||||
|
||||
used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
|
||||
used_stack_ref = ir_CONST_ADDR(used_stack);
|
||||
used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
|
||||
|
||||
if (!is_closure) {
|
||||
used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
|
||||
|
||||
// JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
|
||||
ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
|
||||
if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
|
||||
ir_IF_FALSE(if_internal_func);
|
||||
}
|
||||
// JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
|
||||
ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, func_type_offset));
|
||||
if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
|
||||
ir_IF_FALSE(if_internal_func);
|
||||
|
||||
// JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
|
||||
num_args_ref = ir_CONST_U32(opline->extended_value);
|
||||
|
@ -8541,12 +8539,8 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
|
|||
}
|
||||
ref = ir_SUB_A(used_stack_ref, ref);
|
||||
|
||||
if (is_closure) {
|
||||
used_stack_ref = ref;
|
||||
} else {
|
||||
ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
|
||||
used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
|
||||
}
|
||||
ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
|
||||
used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
|
||||
}
|
||||
|
||||
zend_jit_start_reuse_ip(jit);
|
||||
|
|
32
ext/opcache/tests/jit/gh17307.phpt
Normal file
32
ext/opcache/tests/jit/gh17307.phpt
Normal file
|
@ -0,0 +1,32 @@
|
|||
--TEST--
|
||||
GH-17307 (Internal closure causes JIT failure)
|
||||
--EXTENSIONS--
|
||||
opcache
|
||||
simplexml
|
||||
bcmath
|
||||
--INI--
|
||||
opcache.jit=1254
|
||||
opcache.jit_hot_func=1
|
||||
opcache.jit_buffer_size=32M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$simple = new SimpleXMLElement("<root><a/><b/></root>");
|
||||
|
||||
function run_loop($firstTerms, $closure) {
|
||||
foreach ($firstTerms as $firstTerm) {
|
||||
\debug_zval_dump($firstTerm);
|
||||
$closure($firstTerm, "10");
|
||||
}
|
||||
}
|
||||
|
||||
run_loop($simple, bcadd(...));
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(SimpleXMLElement)#%d (0) refcount(3){
|
||||
}
|
||||
object(SimpleXMLElement)#%d (0) refcount(3){
|
||||
}
|
||||
Done
|
Loading…
Add table
Add a link
Reference in a new issue