Skip to content

Commit 4c8b68e

Browse files
committed
Honor script time limit when calling shutdown functions
A time limit can be set on PHP script execution via set_time_limit() (or .ini file). When the time limit is reached, the OS will notify PHP and a 'timed_out' flag is set. While this flag is regularly checked when executing PHP code, once the end of the script is reached, it is not checked while invoking shutdown functions (registered via register_shutdown_function). Of course, if the shutdown functions are implemented *in* PHP, then the script time limit will be checked while they are running and will take effect. But if the shutdown functions are built-in (implemented in C), it will not. Since the shutdown functions are invoked through zend_call_function, add a check of the 'timed_out' flag there. Then, the script time limit will be respected when *entering* each shutdown function. The fact still remains that if a shutdown function is built-in and runs for a long time, script execution will not time out until it finishes and the interpreter tries to invoke the next one. Still, the behavior of scripts with execution time limits will be more consistent after this patch. To make the execution time-out feature work even more precisely, it would be necessary to scrutinize all the built-in functions and add checks of the 'timed_out' flag in any which can run for a long time. That might not be worth the effort, though. It does appear (to this developer) that the author of the existing (XFAIL) test cases had an odd understanding of how shutdown functions should work. It seemed that they expected that shutdown functions should still run after calling exit(), which is not the case.
1 parent 1a95ed0 commit 4c8b68e

File tree

3 files changed

+5
-5
lines changed

3 files changed

+5
-5
lines changed

Zend/zend_execute_API.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
650650

651651
ZVAL_UNDEF(fci->retval);
652652

653+
if (EG(timed_out)) {
654+
zend_timeout(0);
655+
}
656+
653657
if (!EG(active)) {
654658
return FAILURE; /* executor is already inactive */
655659
}

tests/basic/timeout_variation_10.phpt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ Timeout within shutdown function, variation
55
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
66
if (PHP_OS_FAMILY !== "Windows") die("skip Windows only test");
77
?>
8-
--XFAIL--
9-
Missing timeout check in call_user_function
108
--FILE--
119
<?php
1210

@@ -19,4 +17,5 @@ register_shutdown_function("sleep", 1);
1917
shutdown happens after here
2018
--EXPECTF--
2119
shutdown happens after here
20+
2221
Fatal error: Maximum execution time of 1 second exceeded in %s on line %d

tests/basic/timeout_variation_9.phpt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@ Timeout within shutdown function
55
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
66
if (PHP_OS_FAMILY !== "Windows") die("skip Windows only test");
77
?>
8-
--XFAIL--
9-
Missing timeout check in call_user_function
108
--FILE--
119
<?php
1210

1311
set_time_limit(1);
1412
register_shutdown_function("sleep", 1);
1513
register_shutdown_function("sleep", 1);
1614

17-
exit(0);
1815
?>
1916
never reached here
2017
--EXPECTF--

0 commit comments

Comments
 (0)