diff --git a/NEWS b/NEWS index df82b9d1536..ae8972b71c0 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,8 @@ PHP NEWS - SPL: . Fixed bug GH-16337 (Use-after-free in SplHeap). (nielsdos) + . Fixed bug GH-16464 (Use-after-free in SplDoublyLinkedList::offsetSet()). + (ilutov) - Standard: . Fixed bug GH-16293 (Failed assertion when throwing in assert() callback with diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 74dc3b8c99f..9ae72881aab 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -736,8 +736,10 @@ PHP_METHOD(SplDoublyLinkedList, offsetSet) if (element != NULL) { /* the element is replaced, delref the old one as in * SplDoublyLinkedList::pop() */ - zval_ptr_dtor(&element->data); + zval garbage; + ZVAL_COPY_VALUE(&garbage, &element->data); ZVAL_COPY(&element->data, value); + zval_ptr_dtor(&garbage); } else { zval_ptr_dtor(value); zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset"); diff --git a/ext/spl/tests/gh16464.phpt b/ext/spl/tests/gh16464.phpt new file mode 100644 index 00000000000..7b3b1e80e6f --- /dev/null +++ b/ext/spl/tests/gh16464.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-16464: Use-after-free in SplDoublyLinkedList::offsetSet() when modifying list in destructor of overwritten object +--FILE-- +pop()); + } +} + +$list = new SplDoublyLinkedList; +$list->add(0, new C); +$list[0] = 42; +var_dump($list); + +?> +--EXPECTF-- +int(42) +object(SplDoublyLinkedList)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(0) + ["dllist":"SplDoublyLinkedList":private]=> + array(0) { + } +}