2022年10月7日(金) 22:32 Arnaud Le Blanc <arnaud...@gmail.com>: > Hi internals, > > I would like to propose a way to detect stack overflows before they > happen, with the goal of improving debugability. > > Stack overflows are caused by excessive stack usage, typically due to > deep recursions. Recursion in PHP doesn't use recursion internally, but > some constructs still do, and it is not always possible to avoid without > dramatically increasing complexity or degrading performances. Some > examples of these constructs can be found at [1][2][3]. > > Programs that overflow the stack are terminated with a SIGSEGV, and the > user is left with no hint as to which code is causing the issue. This > makes debugging difficult. > > Xdebug makes debugging easier by throwing an exception when the function > call nesting level exceeds a certain limit [4], which is very useful. > However, this can be overly limiting because this does not discriminate > between the calls that actually use the stack and those that do not. > > Nikita proposed an other solution a while ago [5] that limits in terms > of VM reentrances, so that only the constructs that actually cause > internal recursion count towards the limit. One issue is that not all VM > frames will consume the same amount of stack, and the maximum stack size > depends on the system, so it's hard to determine a good default value > for the limit that is not overly limiting. > > I would like to propose an alternative [6] that limits in terms of stack > size. One issue is that it increases the internals complexity a bit, but > this would make debugging easier without limiting recursion too much > compared to what the system would allow. > > Any thoughts? > > [1] https://bugs.php.net/bug.php?id=64196 > [2] https://bugs.php.net/bug.php?id=75509 > [3] https://github.com/php/php-src/issues/8315 > [4] https://xdebug.org/docs/develop#max_nesting_level > [5] https://externals.io/message/108348 > [6] https://github.com/php/php-src/pull/9104 > > The root cause that users cannot understand what happened is this:
$ php -n -r 'set_error_handler(function ($severity,$message, $filename, $lineno) { throw new ErrorException($message, 0, $severity, $filename, $lineno); }); function f() { f(); } f();' Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes) in Command line code on line 1 When a fatal error happens, PHP does not allow a stack dump. Very old PHP allowed users to catch E_ERROR by user error handler, but it is disabled to prevent users from shooting their own foot. I suppose allowing users to catch "only one" fatal error would solve many issues as well as infinite recursion. Regards, -- Yasuo Ohgaki yohg...@ohgaki.net