为什么PHP中的无限递归函数会导致段错误?

Dav*_*dom 31 php segmentation-fault

一个假设的问题,你们都要咀嚼......

我最近在SO上回答了另一个问题,其中一个PHP脚本是segfaulting,它让我想起了我一直想知道的东西,所以让我们看看是否有人可以对它有所了解.

考虑以下:

<?php

  function segfault ($i = 1) {
    echo "$i\n";
    segfault($i + 1);
  }

  segfault();

?>
Run Code Online (Sandbox Code Playgroud)

显然,这个(无用的)函数无限循环.最终,由于每个对函数的调用都是在前一个调用完成之前执行的,因此会耗尽内存.有点像没有分叉的叉形炸弹.

但是......最终,在POSIX平台上,脚本会死于SIGSEGV(它也会死在Windows上,但更优雅 - 只要我极其有限的低级调试技能可以说明).循环次数取决于系统配置(分配给PHP的内存,32位/ 64位等)和操作系统,但我真正的问题是 - 为什么会发生段错误?

  • 这只是PHP处理"内存不足"错误的方式吗?当然必须有更优雅的方式来处理这个问题?
  • 这是Zend引擎中的错误吗?
  • 有没有什么方法可以在PHP脚本中更好地控制或处理它?
  • 是否有任何设置通常控制可以在函数中进行的最大递归调用次数?

irc*_*ell 24

如果使用XDebug,则最大函数嵌套深度由ini设置控制:

$foo = function() use (&$foo) { 
    $foo();
};
$foo();
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

致命错误:达到最大功能嵌套级别'100',正在中止!

这个恕我直言是比段错误更好的选择,因为它只会杀死当前的脚本,而不是整个过程.

此线程,几年前是内部名单(2006年).他的评论是:

到目前为止,还没有人提出满足这些条件的无限循环问题的解决方案:

  1. 没有误报(即好的代码始终有效)
  2. 执行没有减速
  3. 适用于任何堆栈大小

因此,这个问题仍未得到解决.

现在,由于停止问题,#1完全无法解决.如果你保持堆栈深度的计数器,那么#2是微不足道的(因为你只是在堆栈推送时检查增加的堆栈级别).

最后,#3是一个难以解决的问题.考虑到某些操作系统将以非连续的方式分配堆栈空间,因此不可能以100%的准确率实现,因为无法可移植地获得堆栈大小或使用(对于特定平台,它可能是可能的或甚至很容易,但不是一般的).

相反,PHP应该从XDebug和其他语言(Python等)中获取提示并创建一个可配置的嵌套级别(Python 默认设置为 1000)....

要么是这样,要么在堆栈上捕获内存分配错误以在它发生之前检查段错误并将其转换为一个RecursionLimitException以便您可以恢复....