]> granicus.if.org Git - php/commitdiff
Fix use-after-free in assign-ref compilation
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 13 Sep 2019 15:09:24 +0000 (17:09 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 13 Sep 2019 16:22:14 +0000 (18:22 +0200)
zend_emit_op_data may reallocate the op_array, so the assignment
of the RETURNS_FUNCTION flag may happen on an outdated opline.

Restructure the code a bit to set the flag before calling
zend_emit_op_data().

Zend/zend_compile.c

index 3fc35bedfd8c71e67a37f431590c2431637abda8..494bd3112f179d0f4b69ff8110805d551508d519 100644 (file)
@@ -2822,7 +2822,7 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
 
        znode target_node, source_node;
        zend_op *opline;
-       uint32_t offset;
+       uint32_t offset, flags;
 
        if (is_this_fetch(target_ast)) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
@@ -2851,9 +2851,12 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
        }
 
+       flags = zend_is_call(source_ast) ? ZEND_RETURNS_FUNCTION : 0;
+
        if (opline && opline->opcode == ZEND_FETCH_OBJ_W) {
                opline->opcode = ZEND_ASSIGN_OBJ_REF;
                opline->extended_value &= ~ZEND_FETCH_REF;
+               opline->extended_value |= flags;
                zend_emit_op_data(&source_node);
                if (result != NULL) {
                        *result = target_node;
@@ -2861,17 +2864,14 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
        } else if (opline && opline->opcode == ZEND_FETCH_STATIC_PROP_W) {
                opline->opcode = ZEND_ASSIGN_STATIC_PROP_REF;
                opline->extended_value &= ~ZEND_FETCH_REF;
+               opline->extended_value |= flags;
                zend_emit_op_data(&source_node);
                if (result != NULL) {
                        *result = target_node;
                }
        } else {
                opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node);
-               opline->extended_value = 0;
-       }
-
-       if (zend_is_call(source_ast)) {
-               opline->extended_value |= ZEND_RETURNS_FUNCTION;
+               opline->extended_value = flags;
        }
 }
 /* }}} */