diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-07-07 12:17:11 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-07-07 12:28:35 +0200 |
commit | 2c73bf7e3fc470e8e50cc7283844c9b1d7c2a9d2 (patch) | |
tree | 8e1f2746f4ee9fd761804f3a8bd73085eb0774f3 | |
parent | ecf368b8f2b9d578f3f9bb23f48d5920adbdccbb (diff) | |
parent | 220880ad2d54d10173a250637478da213b1ae8e2 (diff) | |
download | php-git-2c73bf7e3fc470e8e50cc7283844c9b1d7c2a9d2.tar.gz |
Merge branch 'PHP-7.4'
* PHP-7.4:
Fixed bug #78598
-rw-r--r-- | Zend/tests/bug70662.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/bug78598.phpt | 31 | ||||
-rw-r--r-- | Zend/tests/undef_index_to_exception.phpt | 46 | ||||
-rw-r--r-- | Zend/zend_execute.c | 60 |
4 files changed, 130 insertions, 9 deletions
diff --git a/Zend/tests/bug70662.phpt b/Zend/tests/bug70662.phpt index 2bda8141ba..ab540c9d16 100644 --- a/Zend/tests/bug70662.phpt +++ b/Zend/tests/bug70662.phpt @@ -14,5 +14,5 @@ var_dump($a); --EXPECT-- array(1) { ["b"]=> - int(1) + int(2) } diff --git a/Zend/tests/bug78598.phpt b/Zend/tests/bug78598.phpt new file mode 100644 index 0000000000..7e3559f27c --- /dev/null +++ b/Zend/tests/bug78598.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #78598: Changing array during undef index RW error segfaults +--FILE-- +<?php + +$my_var = null; +set_error_handler(function() use(&$my_var) { + $my_var = 0; +}); + +$my_var[0] .= "xyz"; +var_dump($my_var); + +$my_var = null; +$my_var[0][0][0] .= "xyz"; +var_dump($my_var); + +$my_var = null; +$my_var["foo"] .= "xyz"; +var_dump($my_var); + +$my_var = null; +$my_var["foo"]["bar"]["baz"] .= "xyz"; +var_dump($my_var); + +?> +--EXPECT-- +int(0) +int(0) +int(0) +int(0) diff --git a/Zend/tests/undef_index_to_exception.phpt b/Zend/tests/undef_index_to_exception.phpt new file mode 100644 index 0000000000..919b0d47a2 --- /dev/null +++ b/Zend/tests/undef_index_to_exception.phpt @@ -0,0 +1,46 @@ +--TEST-- +Converting undefined index/offset notice to exception +--FILE-- +<?php + +set_error_handler(function($_, $msg) { + throw new Exception($msg); +}); + +$test = []; +try { + $test[0] .= "xyz"; +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +var_dump($test); + +try { + $test["key"] .= "xyz"; +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +var_dump($test); + +unset($test); +try { + $GLOBALS["test"] .= "xyz"; +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump($test); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Undefined offset: 0 +array(0) { +} +Undefined index: key +array(0) { +} +Undefined index: test +Undefined variable $test diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index fcd2a437e6..f49b005a14 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1909,6 +1909,44 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_index(const zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset)); } +static zend_never_inline ZEND_COLD int ZEND_FASTCALL zend_undefined_offset_write( + HashTable *ht, zend_long lval) +{ + /* 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); + } + zend_undefined_offset(lval); + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) { + zend_array_destroy(ht); + return FAILURE; + } + if (EG(exception)) { + return FAILURE; + } + return SUCCESS; +} + +static zend_never_inline ZEND_COLD int ZEND_FASTCALL zend_undefined_index_write( + HashTable *ht, zend_string *offset) +{ + /* 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); + } + zend_undefined_index(offset); + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) { + zend_array_destroy(ht); + return FAILURE; + } + if (EG(exception)) { + return FAILURE; + } + return SUCCESS; +} + static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(const zend_class_entry *ce, const zend_string *method) { zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(method)); @@ -2028,9 +2066,10 @@ num_undef: retval = &EG(uninitialized_zval); break; case BP_VAR_RW: - zend_undefined_offset(hval); - retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval)); - break; + if (UNEXPECTED(zend_undefined_offset_write(ht, hval) == FAILURE)) { + return NULL; + } + /* break missing intentionally */ case BP_VAR_W: retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval)); break; @@ -2058,7 +2097,9 @@ str_index: retval = &EG(uninitialized_zval); break; case BP_VAR_RW: - zend_undefined_index(offset_key); + if (UNEXPECTED(zend_undefined_index_write(ht, offset_key))) { + return NULL; + } /* break missing intentionally */ case BP_VAR_W: ZVAL_NULL(retval); @@ -2076,9 +2117,10 @@ str_index: retval = &EG(uninitialized_zval); break; case BP_VAR_RW: - zend_undefined_index(offset_key); - retval = zend_hash_update(ht, offset_key, &EG(uninitialized_zval)); - break; + if (UNEXPECTED(zend_undefined_index_write(ht, offset_key) == FAILURE)) { + return NULL; + } + /* break missing intentionally */ case BP_VAR_W: retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval)); break; @@ -2143,7 +2185,9 @@ fetch_from_array: } else { retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type EXECUTE_DATA_CC); if (UNEXPECTED(!retval)) { - ZVAL_UNDEF(result); + /* This may fail without throwing if the array was modified while throwing an + * undefined index error. */ + ZVAL_NULL(result); return; } } |