Skip to content

Commit 8796d75

Browse files
committed
Fix GH-21454: Missing write lock validation in SplHeap
Closes GH-21448.
1 parent a563722 commit 8796d75

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ PHP NEWS
3333
. Fixed Set-Cookie parsing bug wrong offset while scanning attributes.
3434
(David Carlier)
3535

36+
- SPL:
37+
. Fixed bug GH-21454 (missing write lock validation in SplHeap).
38+
(ndossche)
39+
3640
- Standard:
3741
. Fixed bug GH-20906 (Assertion failure when messing up output buffers).
3842
(ndossche)

ext/spl/spl_heap.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ static void spl_heap_it_move_forward(zend_object_iterator *iter) /* {{{ */
961961
{
962962
spl_heap_object *object = Z_SPLHEAP_P(&iter->data);
963963

964-
if (UNEXPECTED(spl_heap_consistency_validations(object, false) != SUCCESS)) {
964+
if (UNEXPECTED(spl_heap_consistency_validations(object, true) != SUCCESS)) {
965965
return;
966966
}
967967

@@ -992,6 +992,10 @@ PHP_METHOD(SplHeap, next)
992992
RETURN_THROWS();
993993
}
994994

995+
if (UNEXPECTED(spl_heap_consistency_validations(intern, true) != SUCCESS)) {
996+
RETURN_THROWS();
997+
}
998+
995999
spl_ptr_heap_delete_top(intern->heap, NULL, ZEND_THIS);
9961000
}
9971001
/* }}} */
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
SplHeap::next() write lock
3+
--CREDITS--
4+
cnitlrt
5+
--FILE--
6+
<?php
7+
8+
class EvilPQ extends SplPriorityQueue {
9+
private bool $did = false;
10+
11+
public function compare(mixed $p1, mixed $p2): int {
12+
if (!$this->did) {
13+
$this->did = true;
14+
// Re-entrant write during internal heap insertion comparison.
15+
if (!$this->isEmpty()) {
16+
$this->next(); // no write-lock validation
17+
}
18+
}
19+
return parent::compare($p1, $p2);
20+
}
21+
}
22+
23+
$q = new EvilPQ();
24+
try {
25+
for ($i = 0; $i < 200; $i++) {
26+
$q->insert("d$i", 100 - $i);
27+
}
28+
} catch (RuntimeException $e) {
29+
echo $e::class, ": ", $e->getMessage(), "\n";
30+
}
31+
32+
?>
33+
--EXPECT--
34+
RuntimeException: Heap cannot be changed when it is already being modified.

0 commit comments

Comments
 (0)