# Preventing stack overflows

- Thread: https://externals.io/message/118777
- Original archive: https://news-web.php.net/php.internals/118777
- Started by Arnaud Le Blanc on 2022-10-07T13:32:19+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #118777 — Arnaud Le Blanc — 2022-10-07T13:32:19+00:00

URL: https://externals.io/message/118777#118777

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

---

## #118778 — Yasuo Ohgaki — 2022-10-07T14:14:10+00:00

URL: https://externals.io/message/118777#118778 · In reply to: #118777

2022年10月7日(金) 22:32 Arnaud Le Blanc <arnaud.lb@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
yohgaki@ohgaki.net

---

## #118779 — Arnaud Le Blanc — 2022-10-07T15:08:51+00:00

URL: https://externals.io/message/118777#118779 · In reply to: #118778

> 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.

Fatal errors definitely need improvements.

Stack overflows are even worth, as the process is terminated by the system:

     $ php test.php
     Segmentation fault

With the proposed change, an exception is throw before it happens:

     $ php test.php
     Fatal error: Uncaught Error: Maximum call stack size of 28672 bytes
     reached. Infinite recursion? in test.php:8
     Stack trace:
     #0 test.php(8): C->__destruct()
     #1 test.php(8): C->__destruct()
     #2 test.php(8): C->__destruct()
     ...
     #7 {main}
       thrown in test.php on line 8
