diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index d4450da42009c..e2c090945b6c8 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -961,7 +961,7 @@ static void spl_heap_it_move_forward(zend_object_iterator *iter) /* {{{ */ { spl_heap_object *object = Z_SPLHEAP_P(&iter->data); - if (UNEXPECTED(spl_heap_consistency_validations(object, false) != SUCCESS)) { + if (UNEXPECTED(spl_heap_consistency_validations(object, true) != SUCCESS)) { return; } @@ -992,6 +992,10 @@ PHP_METHOD(SplHeap, next) RETURN_THROWS(); } + if (UNEXPECTED(spl_heap_consistency_validations(intern, true) != SUCCESS)) { + RETURN_THROWS(); + } + spl_ptr_heap_delete_top(intern->heap, NULL, ZEND_THIS); } /* }}} */ diff --git a/ext/spl/tests/heap_next_write_lock.phpt b/ext/spl/tests/heap_next_write_lock.phpt new file mode 100644 index 0000000000000..fcad94f3ccd3f --- /dev/null +++ b/ext/spl/tests/heap_next_write_lock.phpt @@ -0,0 +1,34 @@ +--TEST-- +SplHeap::next() write lock +--CREDITS-- +cnitlrt +--FILE-- +did) { + $this->did = true; + // Re-entrant write during internal heap insertion comparison. + if (!$this->isEmpty()) { + $this->next(); // no write-lock validation + } + } + return parent::compare($p1, $p2); + } +} + +$q = new EvilPQ(); +try { + for ($i = 0; $i < 200; $i++) { + $q->insert("d$i", 100 - $i); + } +} catch (RuntimeException $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +RuntimeException: Heap cannot be changed when it is already being modified.