PHPUnit分段错误

29

当我的开发机(Linux Mint)上的PHPUnit测试失败时,会在我的持续集成服务器(Centos)上引发“分段错误”(Segmentation Fault)。两台机器都运行相同版本的PHPUnit。我的开发机运行PHP 5.3.2-1ubuntu4.9,而CI运行的是PHP 5.2.17。尽管如此,我还是不想将升级PHP作为最后一招。

根据此主题:PHPUnit gets segmentation fault 我尝试了停用/重新安装Xdebug。我没有安装inclue.so。

在CI服务器上,我目前只有两个扩展处于活动状态:php-xml中的dom(phpunit所需)和memcache(框架所需),其他所有扩展均已关闭。


1
请展示如何调用PHPUnit。您尝试过进程隔离吗? - hakre
2
它是每次都崩溃还是只有有时候?另外:您根本不使用任何5.3功能(因此目标是创建5.2兼容软件?-就像@powtac所说,更多的内存可能总是有帮助的 :) - edorian
@edorian - 每次都会崩溃,毫无例外。它应该是5.2兼容的 - 我的实际环境是5.2。 - Rudolf Vavruch
1
@hakre 只有一些测试用例存在这个问题。具体来说,它试图使用创建失败的套接字。 - Rudolf Vavruch
请查看这个问题的答案:https://dev59.com/SWUq5IYBdhLWcg3wT-2D - datashaman
显示剩余7条评论
14个回答

29

在之后,如果升级PHP不是您的选择并且您无法找到segfault源代码的位置,您可以使用调试器进行更多调查。

您可以通过以下方式启动gdb来调试PHPUnit会话:

gdb --args php /usr/bin/phpunit quiz_service_Test.php

然后输入r来运行程序和/或首先设置环境变量。

set env MALLOC_CHECK_=3
r

你可能还考虑在系统上安装 PHP 的调试符号,以获得更好的调试结果。gdb 会在启动时检查此项设置,并留下通知告诉你如何操作。


谢谢,这帮助我缩小了范围。我们从服务器获取的数据对于pcre来说太大了。 - Rudolf Vavruch
好的。你可以限制它,这样preg_...就不会导致段错误,但它也不会完全执行(通常在失败时返回NULL)。请参阅pcre的ini设置 - hakre
对我来说,这是一个没有被phpunit记录下来的堆栈溢出错误;只是一个段错误。 - Benoit Duffez

22

我曾遇到PHPUnit崩溃的问题,但很难找到答案,希望这篇文章能帮助到同样碰到这个问题的人。

PHPUnit会出现崩溃,但只有在以下情况下才会发生:

  • 如果出现错误(或多个错误)
  • 当所有测试已运行完毕但未打印错误时

过了一段时间后,我意识到这是由于使用数据提供程序进行测试失败引起的,特别是当数据提供程序传递了具有许多递归引用的对象时。最终我发现问题所在并进行了一些挖掘:当使用数据提供程序并且测试失败时,PHPUnit尝试创建提供的参数的字符串表示形式以告诉您失败的原因,但是当其中一个参数存在无限递归时,这会成为一个问题。实际上,在PHPUnit_Framework_TestCase :: dataToString()中(大约在1612行附近),PHPUnit会打印使用print_r提供的所有参数,这导致PHP尝试创建无限递归对象的字符串表示形式时发生崩溃。

我采取的解决方案是:

  1. 为所有测试类使用单个基类(幸运的是我已经在这样做了)
  2. 在我的测试基类中重写dataToString(),以检查数据数组中是否存在这些类型的对象(在我的情况下是可能的,因为我知道这些对象的外观)。如果存在该对象,则返回一些特殊值,否则将其传递给父方法。

3
确实很有帮助。更好的方法是在测试本身中创建数据结构,而仅在dataprovider中创建普通数据(这对我很有效)。 - pscheit

11

我曾经遇到过类似的问题,通过在

PHPStorm => 编辑配置 => 解释器选项 : -d zend.enable_gc=0

禁用垃圾回收器来解决问题。或者如果你是从命令行运行测试,可以尝试添加:

-d zend.enable_gc=0


7
当你遇到段错误时,将PHP升级到最新版本。不仅是在软件包管理器中的最新版本,还要使用php.net上可用的最新版本。如果它仍然出现段错误,那么您可以确定问题尚未在PHP本身中得到解决。不要试图摆脱旧版本PHP中的段错误,因为可能已经在更新版本中修复了。
下一步是定位问题:使测试越来越小,直到您无法删除任何内容(但它仍然出现段错误)。如果您有这个,请将测试移动到一个独立的php脚本中,该脚本会出现段错误。现在,您拥有了一个PHP漏洞跟踪器中的漏洞测试脚本。

3

看起来这更像是“临时遮盖”问题而不是真正解决它的方法。也就是说,您正在关闭捕获循环引用的机制,然后删除内存限制器,防止 PHP 吞噬所有 RAM 的机制,这可能会破坏其他东西,例如操作系统。 - Ben A. Hilleli

2
如果有人在Laravel中使用PHPunit遇到这个问题,需要一些时间来弄清楚问题所在。我一直在比较当前代码和上一个版本之间的差异,并通过一些试错最终解决了问题。我有两个不同的模型,它们都使用protected $with覆盖彼此包含。这一定会导致某种循环,phpunit无法处理。希望对某人有用。

1
无限递归通常是导致我们出现此问题的原因。无限递归的症状在使用phpunit运行代码时似乎与在其他环境中运行代码时不同。

1

请更新到最新的XDEBUG。在使用v3.1.5时遇到了相同的错误,升级到3.1.6后一切正常。


使用 Xdebug v3.1.6 仍然面临 Segmentation fault (core dumped) 问题。 - shuba.ivan

1

我曾经遇到过同样的问题,并且找出了原因,是因为我尝试写一个未定义的类变量:

导致分段错误的类(它是一个cakePHP类):

class MyClass extends AppModel {

  protected $classVariableOne;

  public function __construct($id = false, $table = null, $ds = null) {
    parent::__construct($id, $table, $ds);

    $this->classVariableOne =& ClassRegistry::init('ClassVariableOne');

    // This line caused the segmentation fault as the variable doesn't exists
    $this->classVariableTwo =& ClassRegistry::init('ClassVariableTwo');

  }
}

我通过添加第二个变量来修复它:

class MyClass extends AppModel {

  protected $classVariableOne;
  protected $classVariableTwo; // Added this line

  public function __construct($id = false, $table = null, $ds = null) {
    parent::__construct($id, $table, $ds);

    $this->classVariableOne =& ClassRegistry::init('ClassVariableOne');
    $this->classVariableTwo =& ClassRegistry::init('ClassVariableTwo');

  }
}

0

我遇到了同样的问题。我将PHPUnit升级到4.1版本(以运行测试),它能够像Isaac指出的那样显示对象。

因此,如果您遇到这个非常相似的问题,请升级到PHPUnit >= 4.1,您将能够看到错误而不是得到“分段错误”消息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接