Skip to content

Commit 19a1600

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: Don't bail when closing resources on shutdown
2 parents f601910 + 55f4d4c commit 19a1600

File tree

4 files changed

+65
-10
lines changed

4 files changed

+65
-10
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ PHP NEWS
55
- Core:
66
. Fixed bug GH-20113 (Missing new Foo(...) error in constant expressions).
77
(ilutov)
8+
. Fixed bug GH-19844 (Don't bail when closing resources on shutdown). (ilutov)
89

910
- FPM:
1011
. Fixed bug GH-19817 (Decode SCRIPT_FILENAME issue in php 8.5).

Zend/tests/gh19844.phpt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
GH-19844: Bail from stream_close() in zend_shutdown_executor_values()
3+
--SKIPIF--
4+
<?php
5+
if (substr(PHP_OS, 0, 3) == 'WIN') die('skip Aborts with STATUS_BAD_FUNCTION_TABLE on Windows');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
class Test {
11+
public $context;
12+
private static $nested = false;
13+
14+
function stream_open() {
15+
return true;
16+
}
17+
18+
function stream_read() {
19+
return '.';
20+
}
21+
function stream_set_option() {}
22+
function stream_stat() {}
23+
24+
function stream_eof() {
25+
if (!Test::$nested) {
26+
Test::$nested = true;
27+
include 'Test://';
28+
}
29+
@trigger_error('Bail', E_USER_ERROR);
30+
}
31+
32+
function stream_close() {
33+
@trigger_error('Bail', E_USER_ERROR);
34+
}
35+
}
36+
37+
stream_wrapper_register('Test', Test::class);
38+
include 'Test://';
39+
40+
?>
41+
--EXPECTF--
42+
Fatal error: Bail in %s on line %d
43+
44+
Fatal error: Bail in %s on line %d
45+
46+
Fatal error: Bail in %s on line %d

Zend/zend_execute_API.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,7 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
274274
zval *zv;
275275

276276
EG(flags) |= EG_FLAGS_IN_RESOURCE_SHUTDOWN;
277-
zend_try {
278-
zend_close_rsrc_list(&EG(regular_list));
279-
} zend_end_try();
277+
zend_close_rsrc_list(&EG(regular_list));
280278

281279
/* No PHP callback functions should be called after this point. */
282280
EG(active) = 0;

Zend/zend_list.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,25 @@ void zend_close_rsrc_list(HashTable *ht)
217217
/* Reload ht->arData on each iteration, as it may be reallocated. */
218218
uint32_t i = ht->nNumUsed;
219219

220-
while (i-- > 0) {
221-
zval *p = ZEND_HASH_ELEMENT(ht, i);
222-
if (Z_TYPE_P(p) != IS_UNDEF) {
223-
zend_resource *res = Z_PTR_P(p);
224-
if (res->type >= 0) {
225-
zend_resource_dtor(res);
220+
retry:
221+
zend_try {
222+
while (i-- > 0) {
223+
zval *p = ZEND_HASH_ELEMENT(ht, i);
224+
if (Z_TYPE_P(p) != IS_UNDEF) {
225+
zend_resource *res = Z_PTR_P(p);
226+
if (res->type >= 0) {
227+
zend_resource_dtor(res);
228+
}
226229
}
227230
}
228-
}
231+
} zend_catch {
232+
/* If we have bailed, we probably executed user code (e.g. user stream
233+
* API). Keep closing resources so they don't leak. User handlers must be
234+
* called now so they aren't called in zend_deactivate() on
235+
* zend_destroy_rsrc_list(&EG(regular_list)). At that point, the executor
236+
* has already shut down and the process would crash. */
237+
goto retry;
238+
} zend_end_try();
229239
}
230240

231241

0 commit comments

Comments
 (0)