1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 08:12:21 +01:00

Fix GH-8661: Nullsafe in coalesce triggers undefined variable warning

Closes GH-8690
This commit is contained in:
Ilija Tovilo
2022-06-02 17:15:55 +02:00
parent 880803a21e
commit 5a855ee8d6
8 changed files with 70 additions and 28 deletions

2
NEWS
View File

@@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fixed bug GH-8655 (Casting an object to array does not unwrap refcount=1
references). (Nicolas Grekas)
. Fixed bug GH-8661 (Nullsafe in coalesce triggers undefined variable
warning). (ilutov)
- MBString:
. Backwards-compatible mappings for 0x5C/0x7E in Shift-JIS are restored,

View File

@@ -1563,7 +1563,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
SET_RESULT(result, op1);
break;
case ZEND_JMP_NULL:
switch (opline->extended_value) {
switch (opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK) {
case ZEND_SHORT_CIRCUITING_CHAIN_EXPR:
ZVAL_NULL(&zv);
break;

View File

@@ -2457,16 +2457,19 @@ static zend_always_inline zend_result _zend_update_type_info(
COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
break;
case ZEND_JMP_NULL:
if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR) {
{
uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR) {
tmp = MAY_BE_NULL;
} else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
tmp = MAY_BE_FALSE;
} else {
ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
tmp = MAY_BE_TRUE;
}
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
break;
}
case ZEND_ASSIGN_OP:
case ZEND_ASSIGN_DIM_OP:
case ZEND_ASSIGN_OBJ_OP:

View File

@@ -0,0 +1,10 @@
--TEST--
GH-8661: Nullsafe in coalesce triggers undefined variable error
--FILE--
<?php
var_dump($a?->foo ?? null);
?>
--EXPECT--
NULL

View File

@@ -2261,7 +2261,7 @@ static void zend_short_circuiting_commit(uint32_t checkpoint, znode *result, zen
zend_op *opline = &CG(active_op_array)->opcodes[opnum];
opline->op2.opline_num = get_next_op_number();
SET_NODE(opline->result, result);
opline->extended_value =
opline->extended_value |=
ast->kind == ZEND_AST_ISSET ? ZEND_SHORT_CIRCUITING_CHAIN_ISSET :
ast->kind == ZEND_AST_EMPTY ? ZEND_SHORT_CIRCUITING_CHAIN_EMPTY :
ZEND_SHORT_CIRCUITING_CHAIN_EXPR;
@@ -2269,13 +2269,16 @@ static void zend_short_circuiting_commit(uint32_t checkpoint, znode *result, zen
}
}
static void zend_emit_jmp_null(znode *obj_node)
static void zend_emit_jmp_null(znode *obj_node, uint32_t bp_type)
{
uint32_t jmp_null_opnum = get_next_op_number();
zend_op *opline = zend_emit_op(NULL, ZEND_JMP_NULL, obj_node, NULL);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
if (bp_type == BP_VAR_IS) {
opline->extended_value |= ZEND_JMP_NULL_BP_VAR_IS;
}
zend_stack_push(&CG(short_circuiting_opnums), &jmp_null_opnum);
}
@@ -2850,7 +2853,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
}
}
}
zend_emit_jmp_null(&obj_node);
zend_emit_jmp_null(&obj_node, type);
}
}
@@ -4461,7 +4464,7 @@ static void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type
zend_short_circuiting_mark_inner(obj_ast);
zend_compile_expr(&obj_node, obj_ast);
if (nullsafe) {
zend_emit_jmp_null(&obj_node);
zend_emit_jmp_null(&obj_node, type);
}
}

View File

@@ -372,10 +372,14 @@ typedef struct _zend_oparray_context {
/* call through internal function handler. e.g. Closure::invoke() */
#define ZEND_ACC_CALL_VIA_HANDLER ZEND_ACC_CALL_VIA_TRAMPOLINE
#define ZEND_SHORT_CIRCUITING_CHAIN_MASK 0x3
#define ZEND_SHORT_CIRCUITING_CHAIN_EXPR 0
#define ZEND_SHORT_CIRCUITING_CHAIN_ISSET 1
#define ZEND_SHORT_CIRCUITING_CHAIN_EMPTY 2
// Must not clash with ZEND_SHORT_CIRCUITING_CHAIN_MASK
#define ZEND_JMP_NULL_BP_VAR_IS 4
char *zend_visibility_string(uint32_t fn_flags);
typedef struct _zend_property_info {

View File

@@ -7574,19 +7574,23 @@ ZEND_VM_HOT_NOCONST_HANDLER(198, ZEND_JMP_NULL, CONST|TMP|VAR|CV, JMP_ADDR)
}
result = EX_VAR(opline->result.var);
if (EXPECTED(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
if (EXPECTED(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
ZVAL_NULL(result);
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
if (OP1_TYPE == IS_CV
&& UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)
&& (opline->extended_value & ZEND_JMP_NULL_BP_VAR_IS) == 0
) {
SAVE_OPLINE();
ZVAL_UNDEFINED_OP1();
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
} else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
ZVAL_FALSE(result);
} else {
ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZVAL_TRUE(result);
}

48
Zend/zend_vm_execute.h generated
View File

@@ -5244,19 +5244,23 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_NULL_SPEC_CON
}
result = EX_VAR(opline->result.var);
if (EXPECTED(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
if (EXPECTED(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
ZVAL_NULL(result);
if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
if (IS_CONST == IS_CV
&& UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)
&& (opline->extended_value & ZEND_JMP_NULL_BP_VAR_IS) == 0
) {
SAVE_OPLINE();
ZVAL_UNDEFINED_OP1();
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
} else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
ZVAL_FALSE(result);
} else {
ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZVAL_TRUE(result);
}
@@ -19344,19 +19348,23 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_NULL_SPEC_TMP_
}
result = EX_VAR(opline->result.var);
if (EXPECTED(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
if (EXPECTED(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
ZVAL_NULL(result);
if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
if (IS_TMP_VAR == IS_CV
&& UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)
&& (opline->extended_value & ZEND_JMP_NULL_BP_VAR_IS) == 0
) {
SAVE_OPLINE();
ZVAL_UNDEFINED_OP1();
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
} else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
ZVAL_FALSE(result);
} else {
ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZVAL_TRUE(result);
}
@@ -22267,19 +22275,23 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_NULL_SPEC_VAR_
}
result = EX_VAR(opline->result.var);
if (EXPECTED(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
if (EXPECTED(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
ZVAL_NULL(result);
if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
if (IS_VAR == IS_CV
&& UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)
&& (opline->extended_value & ZEND_JMP_NULL_BP_VAR_IS) == 0
) {
SAVE_OPLINE();
ZVAL_UNDEFINED_OP1();
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
} else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
ZVAL_FALSE(result);
} else {
ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZVAL_TRUE(result);
}
@@ -39116,19 +39128,23 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_NULL_SPEC_CV_H
}
result = EX_VAR(opline->result.var);
if (EXPECTED(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK;
if (EXPECTED(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) {
ZVAL_NULL(result);
if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
if (IS_CV == IS_CV
&& UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)
&& (opline->extended_value & ZEND_JMP_NULL_BP_VAR_IS) == 0
) {
SAVE_OPLINE();
ZVAL_UNDEFINED_OP1();
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
} else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
} else if (short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
ZVAL_FALSE(result);
} else {
ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZEND_ASSERT(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
ZVAL_TRUE(result);
}