]> granicus.if.org Git - php/commitdiff
Fix use-after-free with delayed interned memoized const operand
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 4 Oct 2019 08:38:11 +0000 (10:38 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 4 Oct 2019 08:38:11 +0000 (10:38 +0200)
We should addref CONST operands during memoization, as they might
be destroyed by later compilation, e.g. through interning.

Zend/tests/assign_coalesce_006.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/Zend/tests/assign_coalesce_006.phpt b/Zend/tests/assign_coalesce_006.phpt
new file mode 100644 (file)
index 0000000..dfe43b3
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+Null coalesce assign with memoized constant operand that is later interned (OSS-Fuzz #17903)
+--FILE--
+<?php
+$foo[__DIR__] ??= 42;
+var_dump($foo);
+?>
+--EXPECTF--
+array(1) {
+  ["%s"]=>
+  int(42)
+}
index 8f545ce51fa2ed070bb29d7d8213384db352d7b5..9132656d41c6976a7c15bc605f54ecc327dfb221 100644 (file)
@@ -2054,6 +2054,9 @@ static void zend_compile_memoized_expr(znode *result, zend_ast *expr) /* {{{ */
                } else if (result->op_type == IS_TMP_VAR) {
                        zend_emit_op_tmp(&memoized_result, ZEND_COPY_TMP, result, NULL);
                } else {
+                       if (result->op_type == IS_CONST) {
+                               Z_TRY_ADDREF(result->u.constant);
+                       }
                        memoized_result = *result;
                }
 
@@ -7540,7 +7543,11 @@ void zend_compile_coalesce(znode *result, zend_ast *ast) /* {{{ */
 /* }}} */
 
 static void znode_dtor(zval *zv) {
-       efree(Z_PTR_P(zv));
+       znode *node = Z_PTR_P(zv);
+       if (node->op_type == IS_CONST) {
+               zval_ptr_dtor_nogc(&node->u.constant);
+       }
+       efree(node);
 }
 
 void zend_compile_assign_coalesce(znode *result, zend_ast *ast) /* {{{ */