Skip to content

Commit 867ed15

Browse files
committed
Fix GH-18033: NULL-ptr dereference when using register_tick_function in destructor
The problem is that `php_request_shutdown` calls `php_deactivate_ticks` prior to running destructors and the shutdown functions and finalizing output handlers. So if a destructor or shutdown function re-registers a tick function, then the user tick functions handler will be added back to `PG(tick_functions)`. When the next request happens, the list `PG(tick_functions)` still contains an entry to call the user tick functions (added in the previous request during shutdown). This causes a NULL deref eventually because `run_user_tick_functions` assumes that if it is called then `BG(user_tick_functions)` must be non-NULL. Fix this by moving the tick handler deactivation. Closes GH-18047.
1 parent f75dd82 commit 867ed15

File tree

5 files changed

+47
-2
lines changed

5 files changed

+47
-2
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ PHP NEWS
3333
zend.exception_string_param_max_len=0. (timwolla)
3434
. Fixed bug GH-17959 (Relax missing trait fatal error to error exception).
3535
(ilutov)
36+
. Fixed bug GH-18033 (NULL-ptr dereference when using register_tick_function
37+
in destructor). (nielsdos)
3638

3739
- Curl:
3840
. Added curl_multi_get_handles(). (timwolla)

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ PHP 8.5 UPGRADE NOTES
3838
resources that were indirectly collected through cycles.
3939
. It is now allowed to substitute static with self or the concrete class name
4040
in final subclasses.
41+
. The tick handlers are now deactivated after all shutdown functions, destructors
42+
have run and the output handlers have been cleaned up.
43+
This is a consequence of fixing GH-18033.
4144

4245
- Intl:
4346
. The extension now requires at least ICU 57.1.

Zend/tests/declare/gh18033_1.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-18033 (NULL-ptr dereference when using register_tick_function in destructor)
3+
--DESCRIPTION--
4+
Needs --repeat 2 or something similar to reproduce
5+
--CREDITS--
6+
clesmian
7+
--FILE--
8+
<?php
9+
class Foo {
10+
function __destruct() {
11+
declare(ticks=1);
12+
register_tick_function(
13+
function() { }
14+
);
15+
echo "In destructor\n";
16+
}
17+
}
18+
19+
$bar = new Foo;
20+
echo "Done\n";
21+
?>
22+
--EXPECT--
23+
Done
24+
In destructor

Zend/tests/declare/gh18033_2.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-18033 (NULL-ptr dereference when using register_tick_function in ob_start)
3+
--DESCRIPTION--
4+
Needs --repeat 2 or something similar to reproduce
5+
--CREDITS--
6+
clesmian
7+
--FILE--
8+
<?php
9+
ob_start(function() {
10+
declare(ticks=1);
11+
register_tick_function(
12+
function() { }
13+
);
14+
});
15+
?>
16+
--EXPECT--

main/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,8 +1904,6 @@ void php_request_shutdown(void *dummy)
19041904
*/
19051905
EG(current_execute_data) = NULL;
19061906

1907-
php_deactivate_ticks();
1908-
19091907
/* 0. Call any open observer end handlers that are still open after a zend_bailout */
19101908
if (ZEND_OBSERVER_ENABLED) {
19111909
zend_observer_fcall_end_all();
@@ -1926,6 +1924,8 @@ void php_request_shutdown(void *dummy)
19261924
php_output_end_all();
19271925
} zend_end_try();
19281926

1927+
php_deactivate_ticks();
1928+
19291929
/* 4. Reset max_execution_time (no longer executing php code after response sent) */
19301930
zend_try {
19311931
zend_unset_timeout();

0 commit comments

Comments
 (0)