]> granicus.if.org Git - php/commitdiff
Fix by-ref list assign LIST_W+MAKE_REF separation
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 2 Sep 2020 08:23:44 +0000 (10:23 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 2 Sep 2020 08:26:55 +0000 (10:26 +0200)
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 a07c1f56aac1c0f6c8334760009b678cbf9d6138
and the full fix for oss-fuzz #25352.

Zend/zend_compile.c
Zend/zend_execute.c

index 190e7e49d843a60f8530800ab59bedb23901fbd2..8d76148fc2a339d37f239da746c993ff62b48f95 100644 (file)
@@ -2984,10 +2984,10 @@ static void zend_compile_list_assign(
                        zend_handle_numeric_dim(opline, &dim_node);
                }
 
+               if (elem_ast->attr) {
+                       zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL);
+               }
                if (var_ast->kind == ZEND_AST_ARRAY) {
-                       if (elem_ast->attr) {
-                               zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL);
-                       }
                        zend_compile_list_assign(NULL, var_ast, &fetch_result, var_ast->attr);
                } else if (elem_ast->attr) {
                        zend_emit_assign_ref_znode(var_ast, &fetch_result);
@@ -3180,6 +3180,7 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
 
        if ((target_ast->kind != ZEND_AST_VAR
          || target_ast->child[0]->kind != ZEND_AST_ZVAL)
+        && source_ast->kind != ZEND_AST_ZNODE
         && source_node.op_type != IS_CV) {
                /* Both LHS and RHS expressions may modify the same data structure,
                 * and the modification during RHS evaluation may dangle the pointer
index 52260e9f81cc75bdf9b7ef2684a41a9047148ec0..6e66ba72d66cd934832c62671e545e531fa9deac 100644 (file)
@@ -1374,7 +1374,6 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
 {
        const char *msg = NULL;
        const zend_op *opline = EX(opline);
-       const zend_op *end;
        uint32_t var;
 
        if (UNEXPECTED(EG(exception) != NULL)) {
@@ -1396,78 +1395,75 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D)
                        /* TODO: Encode the "reason" into opline->extended_value??? */
                        var = opline->result.var;
                        opline++;
-                       end = EG(current_execute_data)->func->op_array.opcodes +
-                               EG(current_execute_data)->func->op_array.last;
-                       while (opline < end) {
-                               if (opline->op1_type == IS_VAR && opline->op1.var == var) {
-                                       switch (opline->opcode) {
-                                               case ZEND_FETCH_OBJ_W:
-                                               case ZEND_FETCH_OBJ_RW:
-                                               case ZEND_FETCH_OBJ_FUNC_ARG:
-                                               case ZEND_FETCH_OBJ_UNSET:
-                                               case ZEND_ASSIGN_OBJ:
-                                               case ZEND_ASSIGN_OBJ_OP:
-                                               case ZEND_ASSIGN_OBJ_REF:
-                                                       msg = "Cannot use string offset as an object";
-                                                       break;
-                                               case ZEND_FETCH_DIM_W:
-                                               case ZEND_FETCH_DIM_RW:
-                                               case ZEND_FETCH_DIM_FUNC_ARG:
-                                               case ZEND_FETCH_DIM_UNSET:
-                                               case ZEND_FETCH_LIST_W:
-                                               case ZEND_ASSIGN_DIM:
-                                               case ZEND_ASSIGN_DIM_OP:
-                                                       msg = "Cannot use string offset as an array";
-                                                       break;
-                                               case ZEND_ASSIGN_STATIC_PROP_OP:
-                                               case ZEND_ASSIGN_OP:
-                                                       msg = "Cannot use assign-op operators with string offsets";
-                                                       break;
-                                               case ZEND_PRE_INC_OBJ:
-                                               case ZEND_PRE_DEC_OBJ:
-                                               case ZEND_POST_INC_OBJ:
-                                               case ZEND_POST_DEC_OBJ:
-                                               case ZEND_PRE_INC:
-                                               case ZEND_PRE_DEC:
-                                               case ZEND_POST_INC:
-                                               case ZEND_POST_DEC:
-                                                       msg = "Cannot increment/decrement string offsets";
-                                                       break;
-                                               case ZEND_ASSIGN_REF:
-                                               case ZEND_ADD_ARRAY_ELEMENT:
-                                               case ZEND_INIT_ARRAY:
-                                               case ZEND_MAKE_REF:
-                                                       msg = "Cannot create references to/from string offsets";
-                                                       break;
-                                               case ZEND_RETURN_BY_REF:
-                                               case ZEND_VERIFY_RETURN_TYPE:
-                                                       msg = "Cannot return string offsets by reference";
-                                                       break;
-                                               case ZEND_UNSET_DIM:
-                                               case ZEND_UNSET_OBJ:
-                                                       msg = "Cannot unset string offsets";
-                                                       break;
-                                               case ZEND_YIELD:
-                                                       msg = "Cannot yield string offsets by reference";
-                                                       break;
-                                               case ZEND_SEND_REF:
-                                               case ZEND_SEND_VAR_EX:
-                                               case ZEND_SEND_FUNC_ARG:
-                                                       msg = "Only variables can be passed by reference";
-                                                       break;
-                                               case ZEND_FE_RESET_RW:
-                                                       msg = "Cannot iterate on string offsets by reference";
-                                                       break;
-                                               EMPTY_SWITCH_DEFAULT_CASE();
-                                       }
-                                       break;
-                               }
-                               if (opline->op2_type == IS_VAR && opline->op2.var == var) {
-                                       ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
-                                       msg = "Cannot create references to/from string offsets";
-                                       break;
+                       ZEND_ASSERT(opline < execute_data->func->op_array.opcodes +
+                               execute_data->func->op_array.last);
+                       if (opline->op1_type == IS_VAR && opline->op1.var == var) {
+                               switch (opline->opcode) {
+                                       case ZEND_FETCH_OBJ_W:
+                                       case ZEND_FETCH_OBJ_RW:
+                                       case ZEND_FETCH_OBJ_FUNC_ARG:
+                                       case ZEND_FETCH_OBJ_UNSET:
+                                       case ZEND_ASSIGN_OBJ:
+                                       case ZEND_ASSIGN_OBJ_OP:
+                                       case ZEND_ASSIGN_OBJ_REF:
+                                               msg = "Cannot use string offset as an object";
+                                               break;
+                                       case ZEND_FETCH_DIM_W:
+                                       case ZEND_FETCH_DIM_RW:
+                                       case ZEND_FETCH_DIM_FUNC_ARG:
+                                       case ZEND_FETCH_DIM_UNSET:
+                                       case ZEND_FETCH_LIST_W:
+                                       case ZEND_ASSIGN_DIM:
+                                       case ZEND_ASSIGN_DIM_OP:
+                                               msg = "Cannot use string offset as an array";
+                                               break;
+                                       case ZEND_ASSIGN_STATIC_PROP_OP:
+                                       case ZEND_ASSIGN_OP:
+                                               msg = "Cannot use assign-op operators with string offsets";
+                                               break;
+                                       case ZEND_PRE_INC_OBJ:
+                                       case ZEND_PRE_DEC_OBJ:
+                                       case ZEND_POST_INC_OBJ:
+                                       case ZEND_POST_DEC_OBJ:
+                                       case ZEND_PRE_INC:
+                                       case ZEND_PRE_DEC:
+                                       case ZEND_POST_INC:
+                                       case ZEND_POST_DEC:
+                                               msg = "Cannot increment/decrement string offsets";
+                                               break;
+                                       case ZEND_ASSIGN_REF:
+                                       case ZEND_ADD_ARRAY_ELEMENT:
+                                       case ZEND_INIT_ARRAY:
+                                       case ZEND_MAKE_REF:
+                                               msg = "Cannot create references to/from string offsets";
+                                               break;
+                                       case ZEND_RETURN_BY_REF:
+                                       case ZEND_VERIFY_RETURN_TYPE:
+                                               msg = "Cannot return string offsets by reference";
+                                               break;
+                                       case ZEND_UNSET_DIM:
+                                       case ZEND_UNSET_OBJ:
+                                               msg = "Cannot unset string offsets";
+                                               break;
+                                       case ZEND_YIELD:
+                                               msg = "Cannot yield string offsets by reference";
+                                               break;
+                                       case ZEND_SEND_REF:
+                                       case ZEND_SEND_VAR_EX:
+                                       case ZEND_SEND_FUNC_ARG:
+                                               msg = "Only variables can be passed by reference";
+                                               break;
+                                       case ZEND_FE_RESET_RW:
+                                               msg = "Cannot iterate on string offsets by reference";
+                                               break;
+                                       EMPTY_SWITCH_DEFAULT_CASE();
                                }
-                               opline++;
+                               break;
+                       }
+                       if (opline->op2_type == IS_VAR && opline->op2.var == var) {
+                               ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
+                               msg = "Cannot create references to/from string offsets";
+                               break;
                        }
                        break;
                EMPTY_SWITCH_DEFAULT_CASE();