Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Zend/zend_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,21 +214,34 @@ void zend_init_rsrc_plist(void)

void zend_close_rsrc_list(HashTable *ht)
{
/* Reload ht->arData on each iteration, as it may be reallocated. */
uint32_t i = ht->nNumUsed;
uint32_t num = ht->nNumUsed;

retry:
zend_try {
while (i-- > 0) {
/* Reload ht->arData on each iteration, as it may be reallocated. */
zval *p = ZEND_HASH_ELEMENT(ht, i);
if (Z_TYPE_P(p) != IS_UNDEF) {
zend_resource *res = Z_PTR_P(p);
if (res->type >= 0) {
zend_resource_dtor(res);

if (UNEXPECTED(ht->nNumUsed != num)) {
/* New resources were added, reloop from the start.
* We need to keep the top->down order to avoid freeing resources
* in use by the newly created resources. */
i = num = ht->nNumUsed;
}
}
}
}
} zend_catch {
if (UNEXPECTED(ht->nNumUsed != num)) {
/* See above */
i = num = ht->nNumUsed;
}

/* If we have bailed, we probably executed user code (e.g. user stream
* API). Keep closing resources so they don't leak. User handlers must be
* called now so they aren't called in zend_deactivate() on
Expand Down
43 changes: 43 additions & 0 deletions ext/standard/tests/streams/gh20286.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
--TEST--
GH-20286 use after destroy on userland stream_close
--CREDITS--
vi3tL0u1s
--SKIPIF--
<?php
if (substr(PHP_OS, 0, 3) == 'WIN') die('skip Aborts with STATUS_BAD_FUNCTION_TABLE on Windows');
?>
--FILE--
<?php
class lib {
public $context;
function stream_set() {}
function stream_set_option() {}
function stream_stat() {
return true;
}
function stream_open() {
return true;
}

function stream_read($count) {
function a() {}
include('lib://');
}

function stream_close() {
static $count = 0;
if ($count++ < 3) // Prevent infinite loop
include('lib://');
}
}
stream_wrapper_register('lib', lib::class);
include('lib://test.php');
?>
--EXPECTF--
Fatal error: Cannot redeclare a() (previously declared in %s:%d) in %s on line %d

Fatal error: Cannot redeclare a() (previously declared in %s on line %d

Fatal error: Cannot redeclare a() (previously declared in %s on line %d

Fatal error: Cannot redeclare a() (previously declared in %s on line %d
1 change: 1 addition & 0 deletions main/streams/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ typedef struct _php_userstream_data php_userstream_data_t;
static zend_result call_method_if_exists(
zval *object, zval *method_name, zval *retval, uint32_t param_count, zval *params)
{
ZEND_ASSERT(EG(active));
return zend_call_method_if_exists(
Z_OBJ_P(object), Z_STR_P(method_name), retval, param_count, params);
}
Expand Down
Loading