PHPUnit分段故障


PHPUnit Segmentation fault

当PHPUnit测试在我的开发盒(Linux Mint)上正常失败时,它会在我的连续集成盒(Centos)上导致"分段故障"。两台机器都运行相同版本的PHPUnit。我的dev-box运行的是PHP 5.3.2-1ubuntu4.9,CI是PHP 5.2.17。不过,我宁愿把升级PHP作为最后的手段。

根据此线程:PHPUnit出现分段错误我已尝试停用/重新安装Xdebug。我没有安装inclue.so。

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

根据cweiske的建议,如果升级php对您来说不是一个选项,并且您在查找segfault的源时遇到问题,则可以使用调试器来了解更多信息。

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

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

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

set env MALLOC_CHECK_=3
r

您还可以考虑在系统上安装PHP的调试符号,以获得更好的调试结果。gdb在启动时为您检查这一点,并留下一个如何做到这一点的通知。

我遇到了PHPUnit分段错误的问题,很难找到答案,所以希望这能帮助以后解决同样问题的人。

PHPUnit正在分段,但仅限于:

  • 如果出现错误(或不止一个)
  • 在所有测试运行之后,但在打印错误之前

过了一段时间,我意识到这是由于使用数据提供程序的测试失败,特别是对于传递带有大量递归引用的对象的数据提供程序。铃声终于响了,我做了一些挖掘:问题是,当你使用数据提供程序而测试失败时,PHPUnit会尝试为失败描述创建一个所提供参数的字符串表示,以告诉你失败了什么,但当其中一个参数有无限递归时,这是有问题的。事实上,PHPUnit在PHPUnit_Framework_TestCase::dataToString()(第1612行附近)中所做的是打印出数据提供程序使用print_r提供的所有参数,这在PHP试图创建无限递归对象的字符串表示时会导致segfault。

我找到的解决方案是:

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

我遇到了类似的问题,通过禁用中的乱码整理器

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

或者,如果你从命令行运行测试,你可以尝试添加:

-d zend.enable_gc=0

当您得到segfault时,请将您的PHP升级到最新版本。不仅是包管理器中的最新版本,而且是php.net上的最新可用版本。如果它仍然存在segfault,那么您可以确定php本身还没有解决这个问题。不要试图在旧版本的PHP中消除segfault,因为它可能已经在新版本中修复了。

下一步是找出问题:让你的测试越来越小,直到你不能删除任何东西(但它仍然会出错)。如果有,请将测试移到一个独立的php脚本中,该脚本会segfault。现在,您已经在PHP错误跟踪器中为您的错误编写了一个测试脚本。

除了https://stackoverflow.com/a/38789046/246790这对我帮助很大:

您可以使用PHP函数gc_disable();

我已经把它和ini_set('memory_limit', -1); 一起放在了我的PHPUnit引导程序代码中

如果有人在Laravel 中遇到与PHPUnit有关的问题

花了一段时间才弄清楚问题出在哪里。我仔细检查了我当前代码和上一次修订版本之间的差异,经过一些尝试和错误,最终达到了目的。

我有两个不同的模型,它们都包含了protected $with覆盖。

这一定导致了phpunit无法处理的某种循环。

希望有人觉得这很有用。

我也遇到了同样的问题,我试图写一个未定义的类变量:

我的类(它是一个cakeHP类)导致了分段错误:

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');
  }
}

无限递归通常是我们遇到这个问题的原因。在phpunit下运行代码时,无限递归的症状似乎与在其他环境中运行代码时不同。

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

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

因此,如果您遇到同样的问题,请升级到PHPUnit>=4.1,您将能够看到错误,而不是收到"Segmentation fault"消息。

当运行代码覆盖的PHPUnit时,我一直得到一个Segmentation fault: 11。在对分段故障进行堆栈跟踪后,我发现以下是导致分段故障错误的原因:

Program received signal SIGSEGV, Segmentation fault.
0x0000000100b8421a in xdebug_path_info_get_path_for_level () from /usr/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so

我用Komodo远程调试包的最新版本替换了上面路径中当前的xdebug.so,该包是用我的PHP版本(对我来说是5.5)下载的相应包的子文件夹,一切都正常了。

以下为我修复了一个类似的问题(当gdb回溯的输出包括libcurl.solibcrypto.so时):

禁用/etc/php.d/pgsql.ini:

; Enable pgsql extension module
; extension=pgsql.so

编辑/etc/php.d/curl.ini以确保在卷曲:之前包含pgsql.so

; Enable curl extension module
extension=pgsql.so
extension=curl.so
curl.cainfo=/home/statcounter/include/config/cacert.pem

如果您有一个属性指向同一对象的对象,或者其他类型的指针循环,则在运行时会收到此消息

serialize($object);

如果你是Laravel的用户,并且你正在处理模型。如果你认为,你永远不会有这个问题,因为你通过在模型上使用$hidden属性来避免指针循环,请注意,$hidden属性不影响serialize,它只影响到JSONarray的强制转换。

当我将一个模型保存到Mailable对象的属性中时,我遇到了这个问题。

使用修复

$this->model->refresh(); 

__construct方法中,就在整个对象被序列化之前。

这与代码而非扩展有关。在我的情况下,我有这两个文件

  1. 测试用例
  2. 示例测试

测试用例中,有一个名为createApplication的方法。空着吧。
示例测试中,您可以创建方法并填充$this->assertTrue(true)

以上是基本设置,希望您可以根据需要扩展需求。