diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 43b2c020b72..5eceff88dfa 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -728,11 +728,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; } @@ -746,6 +745,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) { + } +}