mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix zend_separate_if_call_and_write for FUNC_ARGs
This commit is contained in:
commit
c2bb9bc0df
6 changed files with 133 additions and 4 deletions
3
NEWS
3
NEWS
|
@ -12,7 +12,8 @@ PHP NEWS
|
|||
(ju1ius)
|
||||
. Fixed OSS Fuzz #61865 (Undef variable in ++/-- for declared property
|
||||
that is unset in error handler). (Girgias)
|
||||
|
||||
. Fixed bug GH-12102 (Incorrect compile error when using array access on TMP
|
||||
value in function call). (ilutov)
|
||||
|
||||
- FPM:
|
||||
. Fixed GH-12077 (PHP 8.3.0RC1 borked socket-close-on-exec.phpt).
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
typedef struct _optimizer_call_info {
|
||||
zend_function *func;
|
||||
zend_op *opline;
|
||||
zend_op *last_check_func_arg_opline;
|
||||
bool is_prototype;
|
||||
bool try_inline;
|
||||
uint32_t func_arg_num;
|
||||
|
@ -235,6 +236,14 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
|||
if (call_stack[call - 1].func_arg_num != (uint32_t)-1
|
||||
&& has_known_send_mode(&call_stack[call - 1], call_stack[call - 1].func_arg_num)) {
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, call_stack[call - 1].func_arg_num)) {
|
||||
/* There's no TMP specialization for FETCH_OBJ_W/FETCH_DIM_W. Avoid
|
||||
* converting it and error at runtime in the FUNC_ARG variant. */
|
||||
if ((opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG)
|
||||
&& (opline->op1_type == IS_TMP_VAR || call_stack[call - 1].last_check_func_arg_opline == NULL)) {
|
||||
/* Don't remove the associated CHECK_FUNC_ARG opcode. */
|
||||
call_stack[call - 1].last_check_func_arg_opline = NULL;
|
||||
break;
|
||||
}
|
||||
if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) {
|
||||
opline->opcode -= 9;
|
||||
} else {
|
||||
|
@ -278,11 +287,21 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
|||
|
||||
if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) {
|
||||
call_stack[call - 1].func_arg_num = opline->op2.num;
|
||||
MAKE_NOP(opline);
|
||||
call_stack[call - 1].last_check_func_arg_opline = opline;
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAR_EX:
|
||||
case ZEND_SEND_FUNC_ARG:
|
||||
/* Don't transform SEND_FUNC_ARG if any FETCH opcodes weren't transformed. */
|
||||
if (call_stack[call - 1].last_check_func_arg_opline == NULL) {
|
||||
if (opline->op2_type == IS_CONST) {
|
||||
call_stack[call - 1].try_inline = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
MAKE_NOP(call_stack[call - 1].last_check_func_arg_opline);
|
||||
call_stack[call - 1].last_check_func_arg_opline = NULL;
|
||||
ZEND_FALLTHROUGH;
|
||||
case ZEND_SEND_VAR_EX:
|
||||
if (opline->op2_type == IS_CONST) {
|
||||
call_stack[call - 1].try_inline = 0;
|
||||
break;
|
||||
|
|
30
Zend/tests/gh12102_1.phpt
Normal file
30
Zend/tests/gh12102_1.phpt
Normal file
|
@ -0,0 +1,30 @@
|
|||
--TEST--
|
||||
GH-12102: Incorrect "Cannot use temporary expression in write context" error for BP_VAR_FUNC_ARG
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test() {
|
||||
byVal(func_get_args()[0]);
|
||||
try {
|
||||
byRef(func_get_args()[0]);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/* Intentionally declared after test() to avoid compile-time checking of ref args. */
|
||||
|
||||
function byVal($arg) {
|
||||
var_dump($arg);
|
||||
}
|
||||
|
||||
function byRef(&$arg) {
|
||||
var_dump($arg);
|
||||
}
|
||||
|
||||
test('y');
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(1) "y"
|
||||
Cannot use temporary expression in write context
|
43
Zend/tests/gh12102_2.phpt
Normal file
43
Zend/tests/gh12102_2.phpt
Normal file
|
@ -0,0 +1,43 @@
|
|||
--TEST--
|
||||
GH-12102: Incorrect "Cannot use temporary expression in write context" error for BP_VAR_FUNC_ARG
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test() {
|
||||
global $ref;
|
||||
byVal(getRef()[0]);
|
||||
var_dump($ref);
|
||||
byRef(getRef()[0]);
|
||||
var_dump($ref);
|
||||
}
|
||||
|
||||
/* Intentionally declared after test() to avoid compile-time checking of ref args. */
|
||||
|
||||
function &getRef() {
|
||||
global $ref;
|
||||
$ref = [];
|
||||
return $ref;
|
||||
}
|
||||
|
||||
function byVal($arg) {
|
||||
$arg[] = 42;
|
||||
}
|
||||
|
||||
function byRef(&$arg) {
|
||||
$arg[] = 42;
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Undefined array key 0 in %s on line %d
|
||||
array(0) {
|
||||
}
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(42)
|
||||
}
|
||||
}
|
32
Zend/tests/gh12102_3.phpt
Normal file
32
Zend/tests/gh12102_3.phpt
Normal file
|
@ -0,0 +1,32 @@
|
|||
--TEST--
|
||||
GH-12102: Incorrect "Cannot use temporary expression in write context" error for BP_VAR_FUNC_ARG
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test() {
|
||||
byVal(C[0]);
|
||||
try {
|
||||
byRef(C[0]);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/* Intentionally declared after test() to avoid compile-time checking of ref args. */
|
||||
|
||||
const C = ['foo'];
|
||||
|
||||
function byVal($arg) {
|
||||
var_dump($arg);
|
||||
}
|
||||
|
||||
function byRef(&$arg) {
|
||||
var_dump($arg);
|
||||
}
|
||||
|
||||
test('y');
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "foo"
|
||||
Cannot use temporary expression in write context
|
|
@ -2929,7 +2929,11 @@ static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t t
|
|||
|
||||
static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type) /* {{{ */
|
||||
{
|
||||
if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) {
|
||||
if (type != BP_VAR_R
|
||||
&& type != BP_VAR_IS
|
||||
/* Whether a FUNC_ARG is R may only be determined at runtime. */
|
||||
&& type != BP_VAR_FUNC_ARG
|
||||
&& zend_is_call(ast)) {
|
||||
if (node->op_type == IS_VAR) {
|
||||
zend_op *opline = zend_emit_op(NULL, ZEND_SEPARATE, node, NULL);
|
||||
opline->result_type = IS_VAR;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue