]> granicus.if.org Git - php/commitdiff
Fixed bug #79784
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 7 Jul 2020 12:22:58 +0000 (14:22 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 7 Jul 2020 12:22:58 +0000 (14:22 +0200)
The fix here is essentially the same as for bug #78598, just for
the undefined variable notice, rather than the undefined index one.

NEWS
Zend/tests/bug79784.phpt [new file with mode: 0644]
Zend/zend_execute.c

diff --git a/NEWS b/NEWS
index 7a0df9806a1f584e58f009ae1d5137227274fd55..bfe7b596ebfc9347263e048144c357e476e0131b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,8 @@ PHP                                                                        NEWS
     (Nikita)
   . Fixed bug #78598 (Changing array during undef index RW error segfaults).
     (Nikita)
+  . Fixed bug #79784 (Use after free if changing array during undef var during
+    array write fetch). (Nikita)
 
 - Fileinfo:
   . Fixed bug #79756 (finfo_file crash (FILEINFO_MIME)). (cmb)
diff --git a/Zend/tests/bug79784.phpt b/Zend/tests/bug79784.phpt
new file mode 100644 (file)
index 0000000..be1cd72
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #79784: Use after free if changing array during undef var during array write fetch
+--FILE--
+<?php
+set_error_handler(function () {
+    $GLOBALS['a'] = null;
+});
+
+$a[$c] = 'x' ;
+var_dump($a);
+$a[$c] .= 'x' ;
+var_dump($a);
+$a[$c][$c] = 'x' ;
+var_dump($a);
+
+?>
+--EXPECT--
+NULL
+NULL
+NULL
index 7b27c5a3a506070cec9f3a3b1e193de9bde2d030..5aed92ff45250e3d0f6af93d3e833120b0389042 100644 (file)
@@ -2067,12 +2067,25 @@ static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim
        FREE_OP(free_op_data1);
 }
 
-static zend_never_inline zend_uchar slow_index_convert(const zval *dim, zend_value *value EXECUTE_DATA_DC)
+static zend_never_inline zend_uchar slow_index_convert(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC)
 {
        switch (Z_TYPE_P(dim)) {
-               case IS_UNDEF:
+               case IS_UNDEF: {
+                       /* The array may be destroyed while throwing the notice.
+                        * Temporarily increase the refcount to detect this situation. */
+                       if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
+                               GC_ADDREF(ht);
+                       }
                        ZVAL_UNDEFINED_OP2();
+                       if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
+                               zend_array_destroy(ht);
+                               return IS_NULL;
+                       }
+                       if (EG(exception)) {
+                               return IS_NULL;
+                       }
                        /* break missing intentionally */
+               }
                case IS_NULL:
                        value->str = ZSTR_EMPTY_ALLOC();
                        return IS_STRING;
@@ -2182,7 +2195,7 @@ str_index:
                goto try_again;
        } else {
                zend_value val;
-               zend_uchar t = slow_index_convert(dim, &val EXECUTE_DATA_CC);
+               zend_uchar t = slow_index_convert(ht, dim, &val EXECUTE_DATA_CC);
 
                if (t == IS_STRING) {
                        offset_key = val.str;