From 883ab9be268caac06fc3cdaa633c2681c5a26748 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 9 Jan 2026 17:14:11 +0100 Subject: [PATCH] Fix GH-20856: heap-use-after-free in SplDoublyLinkedList iterator when modifying during iteration The element may be still in use in other places, so the linking pointers should be kept consistent. If not consistent, the "move forward" code in the sample test will read a stale, dangling pointer. --- ext/spl/spl_dllist.c | 7 +++++-- ext/spl/tests/gh20856.phpt | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 ext/spl/tests/gh20856.phpt diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 5a78db2921a81..2ac7980a86cb6 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 neightbors */ + /* 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 0000000000000..8bc1b3c95827c --- /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) { + } +}