Skip to content

Commit

Permalink
Fix uouv on oom on object allocation
Browse files Browse the repository at this point in the history
We should initialize object handlers before trying to allocate more memory,
because if we OOM we'll look for the free_obj handler which has not been
initialized. Furthermore, free_obj can run before the object is fully
initialized, requiring guards for potentially unset fields.

Fixes phpGH-11734
  • Loading branch information
iluuu1994 committed Aug 2, 2023
1 parent b0bc057 commit d32ab68
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 2 deletions.
15 changes: 15 additions & 0 deletions Zend/tests/new_oom.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

$mb_used = (int) ceil(memory_get_usage() / (1024 ** 2));
ini_set('memory_limit', ($mb_used + 1) . 'M');

$class = $argv[1];
$objects = [];

try {
while (true) {
$rc = new ReflectionClass($class);
$objects[] = $rc->newInstanceWithoutConstructor();
}
} catch (Throwable) {
}
24 changes: 24 additions & 0 deletions Zend/tests/new_oom.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Test OOM on new of each class
--SKIPIF--
<?php
if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
?>
--FILE--
<?php

$file = __DIR__ . '/new_oom.inc';
$php = PHP_BINARY;

foreach (get_declared_classes() as $class) {
$output = shell_exec("$php $file $class");
if ($output && preg_match('(^\nFatal error: Allowed memory size of [0-9]+ bytes exhausted[^\r\n]* \(tried to allocate [0-9]+ bytes\) in [^\r\n]+ on line [0-9]+$)', $output) !== 1) {
echo "Class $class failed\n";
echo $output;
}
}

?>
===DONE===
--EXPECT--
===DONE===
9 changes: 7 additions & 2 deletions ext/spl/spl_heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ static spl_ptr_heap *spl_ptr_heap_clone(spl_ptr_heap *from) { /* {{{ */
static void spl_ptr_heap_destroy(spl_ptr_heap *heap) { /* {{{ */
int i;

/* Heap might be null if we OOMed during object initialization. */
if (!heap) {
return;
}

for (i = 0; i < heap->count; ++i) {
heap->dtor(spl_heap_elem(heap, i));
}
Expand Down Expand Up @@ -438,18 +443,18 @@ static zend_object *spl_heap_object_new_ex(zend_class_entry *class_type, zend_ob

while (parent) {
if (parent == spl_ce_SplPriorityQueue) {
intern->heap = spl_ptr_heap_init(spl_ptr_pqueue_elem_cmp, spl_ptr_heap_pqueue_elem_ctor, spl_ptr_heap_pqueue_elem_dtor, sizeof(spl_pqueue_elem));
intern->std.handlers = &spl_handler_SplPriorityQueue;
intern->heap = spl_ptr_heap_init(spl_ptr_pqueue_elem_cmp, spl_ptr_heap_pqueue_elem_ctor, spl_ptr_heap_pqueue_elem_dtor, sizeof(spl_pqueue_elem));
intern->flags = SPL_PQUEUE_EXTR_DATA;
break;
}

if (parent == spl_ce_SplMinHeap || parent == spl_ce_SplMaxHeap
|| parent == spl_ce_SplHeap) {
intern->std.handlers = &spl_handler_SplHeap;
intern->heap = spl_ptr_heap_init(
parent == spl_ce_SplMinHeap ? spl_ptr_heap_zval_min_cmp : spl_ptr_heap_zval_max_cmp,
spl_ptr_heap_zval_ctor, spl_ptr_heap_zval_dtor, sizeof(zval));
intern->std.handlers = &spl_handler_SplHeap;
break;
}

Expand Down

0 comments on commit d32ab68

Please sign in to comment.