diff --git a/NEWS b/NEWS index 2ef6a9975b4..43216c00012 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,10 @@ PHP NEWS . Fixed bug GH-18139 (Memory leak when overriding some settings via readline_info()). (ndossche) +- SPL: + . Fixed bug GH-20856 (heap-use-after-free in SplDoublyLinkedList iterator + when modifying during iteration). (ndossche) + - Standard: . Fixed bug #74357 (lchown fails to change ownership of symlink with ZTS) (Jakub Zelenka) diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 0f525e627d3..2ac7980a86c 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -764,11 +764,10 @@ PHP_METHOD(SplDoublyLinkedList, offsetUnset) element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); if (element != NULL) { - /* connect the neighbors */ + /* disconnect the neighbours */ if (element->prev) { element->prev->next = element->next; } - if (element->next) { element->next->prev = element->prev; } @@ -782,6 +781,10 @@ PHP_METHOD(SplDoublyLinkedList, offsetUnset) llist->tail = element->prev; } + /* Keep consistency if element is kept alive. */ + element->prev = NULL; + element->next = NULL; + /* finally, delete the element */ llist->count--; diff --git a/ext/spl/tests/gh20856.phpt b/ext/spl/tests/gh20856.phpt new file mode 100644 index 00000000000..8bc1b3c9582 --- /dev/null +++ b/ext/spl/tests/gh20856.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-20856 (heap-use-after-free in SplDoublyLinkedList iterator when modifying during iteration) +--CREDITS-- +vi3tL0u1s +iluuu1994 +--FILE-- + +--EXPECTF-- +object(SplStack)#%d (%d) { + ["flags":"SplDoublyLinkedList":private]=> + int(6) + ["dllist":"SplDoublyLinkedList":private]=> + array(0) { + } +}