Skip to content

Commit

Permalink
Fix uouv on oom on object allocation
Browse files Browse the repository at this point in the history
We may OOM during object initialization. In this case, free_obj needs to guard
against NULL values. There may be more cases where this is an issue, these were
the ones I was able to discover via script.

Fixes GH-11734
  • Loading branch information
iluuu1994 committed Aug 14, 2023
1 parent 2196e22 commit ee000ea
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 9 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ PHP NEWS

- Core:
. Fixed strerror_r detection at configuration time. (Kévin Dunglas)
. Fixed segfault during freeing of some incompletely initialized objects due
to OOM error (PDO, SPL, XSL). (ilutov)

- DOM:
. adoptNode now respects the strict error checking property. (nielsdos)
Expand Down
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 2>&1");
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, "\n";
}
}

?>
===DONE===
--EXPECT--
===DONE===
6 changes: 6 additions & 0 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,12 @@ static void dbh_free(pdo_dbh_t *dbh, bool free_persistent)
static void pdo_dbh_free_storage(zend_object *std)
{
pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(std);

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

if (dbh->driver_data && dbh->methods && dbh->methods->rollback && pdo_is_in_transaction(dbh)) {
dbh->methods->rollback(dbh);
dbh->in_txn = false;
Expand Down
11 changes: 6 additions & 5 deletions ext/spl/spl_dllist.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,13 @@ static void spl_dllist_object_free_storage(zend_object *object) /* {{{ */

zend_object_std_dtor(&intern->std);

while (intern->llist->count > 0) {
spl_ptr_llist_pop(intern->llist, &tmp);
zval_ptr_dtor(&tmp);
if (intern->llist) {
while (intern->llist->count > 0) {
spl_ptr_llist_pop(intern->llist, &tmp);
zval_ptr_dtor(&tmp);
}
spl_ptr_llist_destroy(intern->llist);
}

spl_ptr_llist_destroy(intern->llist);
SPL_LLIST_CHECK_DELREF(intern->traverse_pointer);
}
/* }}} */
Expand Down
5 changes: 5 additions & 0 deletions ext/spl/spl_heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ static spl_ptr_heap *spl_ptr_heap_clone(spl_ptr_heap *from) { /* {{{ */
/* }}} */

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

int i;

for (i = 0; i < heap->count; ++i) {
Expand Down
12 changes: 8 additions & 4 deletions ext/xsl/php_xsl.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@ void xsl_objects_free_storage(zend_object *object)

zend_object_std_dtor(&intern->std);

zend_hash_destroy(intern->parameter);
FREE_HASHTABLE(intern->parameter);
if (intern->parameter) {
zend_hash_destroy(intern->parameter);
FREE_HASHTABLE(intern->parameter);
}

zend_hash_destroy(intern->registered_phpfunctions);
FREE_HASHTABLE(intern->registered_phpfunctions);
if (intern->registered_phpfunctions) {
zend_hash_destroy(intern->registered_phpfunctions);
FREE_HASHTABLE(intern->registered_phpfunctions);
}

if (intern->node_list) {
zend_hash_destroy(intern->node_list);
Expand Down

0 comments on commit ee000ea

Please sign in to comment.