Skip to content

Commit 8b6b2bd

Browse files
committed
Fix by-ref list assign LIST_W+MAKE_REF separation
Shift the responsibility for emitting MAKE_REF to the list assignment code, to make sure that LIST_W and MAKE_REF are directly adjacent, and there are no opcodes in between that could modify the LIST_W result. Additionally, adjust the zend_wrong_string_offset() code to not perform a loop over opcodes and assert that the next opcode is a relevant one. The VM write-safety model requires this. This is a followup to a07c1f5 and the full fix for oss-fuzz #25352.
1 parent aedc7b0 commit 8b6b2bd

File tree

2 files changed

+72
-75
lines changed

2 files changed

+72
-75
lines changed

Zend/zend_compile.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,10 +2984,10 @@ static void zend_compile_list_assign(
29842984
zend_handle_numeric_dim(opline, &dim_node);
29852985
}
29862986

2987+
if (elem_ast->attr) {
2988+
zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL);
2989+
}
29872990
if (var_ast->kind == ZEND_AST_ARRAY) {
2988-
if (elem_ast->attr) {
2989-
zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL);
2990-
}
29912991
zend_compile_list_assign(NULL, var_ast, &fetch_result, var_ast->attr);
29922992
} else if (elem_ast->attr) {
29932993
zend_emit_assign_ref_znode(var_ast, &fetch_result);
@@ -3180,6 +3180,7 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
31803180

31813181
if ((target_ast->kind != ZEND_AST_VAR
31823182
|| target_ast->child[0]->kind != ZEND_AST_ZVAL)
3183+
&& source_ast->kind != ZEND_AST_ZNODE
31833184
&& source_node.op_type != IS_CV) {
31843185
/* Both LHS and RHS expressions may modify the same data structure,
31853186
* and the modification during RHS evaluation may dangle the pointer

Zend/zend_execute.c

Lines changed: 68 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,7 +1374,6 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
13741374
{
13751375
const char *msg = NULL;
13761376
const zend_op *opline = EX(opline);
1377-
const zend_op *end;
13781377
uint32_t var;
13791378

13801379
if (UNEXPECTED(EG(exception) != NULL)) {
@@ -1396,78 +1395,75 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
13961395
/* TODO: Encode the "reason" into opline->extended_value??? */
13971396
var = opline->result.var;
13981397
opline++;
1399-
end = EG(current_execute_data)->func->op_array.opcodes +
1400-
EG(current_execute_data)->func->op_array.last;
1401-
while (opline < end) {
1402-
if (opline->op1_type == IS_VAR && opline->op1.var == var) {
1403-
switch (opline->opcode) {
1404-
case ZEND_FETCH_OBJ_W:
1405-
case ZEND_FETCH_OBJ_RW:
1406-
case ZEND_FETCH_OBJ_FUNC_ARG:
1407-
case ZEND_FETCH_OBJ_UNSET:
1408-
case ZEND_ASSIGN_OBJ:
1409-
case ZEND_ASSIGN_OBJ_OP:
1410-
case ZEND_ASSIGN_OBJ_REF:
1411-
msg = "Cannot use string offset as an object";
1412-
break;
1413-
case ZEND_FETCH_DIM_W:
1414-
case ZEND_FETCH_DIM_RW:
1415-
case ZEND_FETCH_DIM_FUNC_ARG:
1416-
case ZEND_FETCH_DIM_UNSET:
1417-
case ZEND_FETCH_LIST_W:
1418-
case ZEND_ASSIGN_DIM:
1419-
case ZEND_ASSIGN_DIM_OP:
1420-
msg = "Cannot use string offset as an array";
1421-
break;
1422-
case ZEND_ASSIGN_STATIC_PROP_OP:
1423-
case ZEND_ASSIGN_OP:
1424-
msg = "Cannot use assign-op operators with string offsets";
1425-
break;
1426-
case ZEND_PRE_INC_OBJ:
1427-
case ZEND_PRE_DEC_OBJ:
1428-
case ZEND_POST_INC_OBJ:
1429-
case ZEND_POST_DEC_OBJ:
1430-
case ZEND_PRE_INC:
1431-
case ZEND_PRE_DEC:
1432-
case ZEND_POST_INC:
1433-
case ZEND_POST_DEC:
1434-
msg = "Cannot increment/decrement string offsets";
1435-
break;
1436-
case ZEND_ASSIGN_REF:
1437-
case ZEND_ADD_ARRAY_ELEMENT:
1438-
case ZEND_INIT_ARRAY:
1439-
case ZEND_MAKE_REF:
1440-
msg = "Cannot create references to/from string offsets";
1441-
break;
1442-
case ZEND_RETURN_BY_REF:
1443-
case ZEND_VERIFY_RETURN_TYPE:
1444-
msg = "Cannot return string offsets by reference";
1445-
break;
1446-
case ZEND_UNSET_DIM:
1447-
case ZEND_UNSET_OBJ:
1448-
msg = "Cannot unset string offsets";
1449-
break;
1450-
case ZEND_YIELD:
1451-
msg = "Cannot yield string offsets by reference";
1452-
break;
1453-
case ZEND_SEND_REF:
1454-
case ZEND_SEND_VAR_EX:
1455-
case ZEND_SEND_FUNC_ARG:
1456-
msg = "Only variables can be passed by reference";
1457-
break;
1458-
case ZEND_FE_RESET_RW:
1459-
msg = "Cannot iterate on string offsets by reference";
1460-
break;
1461-
EMPTY_SWITCH_DEFAULT_CASE();
1462-
}
1463-
break;
1464-
}
1465-
if (opline->op2_type == IS_VAR && opline->op2.var == var) {
1466-
ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
1467-
msg = "Cannot create references to/from string offsets";
1468-
break;
1398+
ZEND_ASSERT(opline < execute_data->func->op_array.opcodes +
1399+
execute_data->func->op_array.last);
1400+
if (opline->op1_type == IS_VAR && opline->op1.var == var) {
1401+
switch (opline->opcode) {
1402+
case ZEND_FETCH_OBJ_W:
1403+
case ZEND_FETCH_OBJ_RW:
1404+
case ZEND_FETCH_OBJ_FUNC_ARG:
1405+
case ZEND_FETCH_OBJ_UNSET:
1406+
case ZEND_ASSIGN_OBJ:
1407+
case ZEND_ASSIGN_OBJ_OP:
1408+
case ZEND_ASSIGN_OBJ_REF:
1409+
msg = "Cannot use string offset as an object";
1410+
break;
1411+
case ZEND_FETCH_DIM_W:
1412+
case ZEND_FETCH_DIM_RW:
1413+
case ZEND_FETCH_DIM_FUNC_ARG:
1414+
case ZEND_FETCH_DIM_UNSET:
1415+
case ZEND_FETCH_LIST_W:
1416+
case ZEND_ASSIGN_DIM:
1417+
case ZEND_ASSIGN_DIM_OP:
1418+
msg = "Cannot use string offset as an array";
1419+
break;
1420+
case ZEND_ASSIGN_STATIC_PROP_OP:
1421+
case ZEND_ASSIGN_OP:
1422+
msg = "Cannot use assign-op operators with string offsets";
1423+
break;
1424+
case ZEND_PRE_INC_OBJ:
1425+
case ZEND_PRE_DEC_OBJ:
1426+
case ZEND_POST_INC_OBJ:
1427+
case ZEND_POST_DEC_OBJ:
1428+
case ZEND_PRE_INC:
1429+
case ZEND_PRE_DEC:
1430+
case ZEND_POST_INC:
1431+
case ZEND_POST_DEC:
1432+
msg = "Cannot increment/decrement string offsets";
1433+
break;
1434+
case ZEND_ASSIGN_REF:
1435+
case ZEND_ADD_ARRAY_ELEMENT:
1436+
case ZEND_INIT_ARRAY:
1437+
case ZEND_MAKE_REF:
1438+
msg = "Cannot create references to/from string offsets";
1439+
break;
1440+
case ZEND_RETURN_BY_REF:
1441+
case ZEND_VERIFY_RETURN_TYPE:
1442+
msg = "Cannot return string offsets by reference";
1443+
break;
1444+
case ZEND_UNSET_DIM:
1445+
case ZEND_UNSET_OBJ:
1446+
msg = "Cannot unset string offsets";
1447+
break;
1448+
case ZEND_YIELD:
1449+
msg = "Cannot yield string offsets by reference";
1450+
break;
1451+
case ZEND_SEND_REF:
1452+
case ZEND_SEND_VAR_EX:
1453+
case ZEND_SEND_FUNC_ARG:
1454+
msg = "Only variables can be passed by reference";
1455+
break;
1456+
case ZEND_FE_RESET_RW:
1457+
msg = "Cannot iterate on string offsets by reference";
1458+
break;
1459+
EMPTY_SWITCH_DEFAULT_CASE();
14691460
}
1470-
opline++;
1461+
break;
1462+
}
1463+
if (opline->op2_type == IS_VAR && opline->op2.var == var) {
1464+
ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
1465+
msg = "Cannot create references to/from string offsets";
1466+
break;
14711467
}
14721468
break;
14731469
EMPTY_SWITCH_DEFAULT_CASE();

0 commit comments

Comments
 (0)