Tag Archives: xdebug

调试一个 xdebug 造成的 Segmentation fault

在调试一个用了 solr 扩展的 php 代码时候,发现调用 query 会发生 Segmentation fault 。于是想知道是从什么地方来的错误。开始觉得是 solr 扩展的问题。但是只有一个 Segmentation fault 不好定位。所以就先搞出 coredump 出来。先写一个简单的复现程序 test.php ,就是简单地初始化好 solr ,然后调用一次 query ,然后打开 coredump,运行一下。

ulimit -c unlimited
php test.php

这就在当前目录下产生了一个 core 文件。然后就可以上 gdb 了

gdb core test.php
.....
(gdb) bt
#0  zend_memrchr (type=1, error_filename=, error_lineno=34, format=, args=)
    at /usr/local/include/php/Zend/zend_operators.h:291
#1  xdebug_error_cb (type=1, error_filename=, error_lineno=34, format=, args=)
    at /home/xiezhenye/xdebug-2.2.1/xdebug_stack.c:626
#2  0x000000000076ac0e in zend_error_va (type=718182544, file=0xa 
, lineno=4294967295, format=0x10
) at /home/xiezhenye/php-5.4.7/Zend/zend_exceptions.c:767 #3 0x000000000076ad8e in zend_exception_error (exception=0x7fcc2ace1600, severity=1) at /home/xiezhenye/php-5.4.7/Zend/zend_exceptions.c:807 #4 0x0000000000752aba in zend_execute_scripts (type=8, retval=, file_count=3) at /home/xiezhenye/php-5.4.7/Zend/zend.c:1310 #5 0x00000000006f72fd in php_execute_script (primary_file=) at /home/xiezhenye/php-5.4.7/main/main.c:2473 #6 0x00000000007f98ac in do_cli (argc=, argv=) at /home/xiezhenye/php-5.4.7/sapi/cli/php_cli.c:988 #7 0x00000000007f9fe4 in main (argc=, argv=) at /home/xiezhenye/php-5.4.7/sapi/cli/php_cli.c:1364 (gdb)

发现调用栈里没有 solr 的东西,最可疑的倒是 xdebug_error_cb 。看起来可能是 xdebug 的问题。于是先禁用掉 xdebug ,果然一切就正常了,输出了 solr 的爆长的异常信息。

于是去看看 xdebug 的那段代码 xdebug_stack.c 626 行。附近几行是这样的:

 623                                 /* find first new line */
 624                                 p = strchr(buffer, '\n');
 625                                 /* find last quote */
 626                                 p = ((char *) zend_memrchr(buffer, '\'', p - buffer)) + 1;
 627                                 /* Create new buffer */
 628                                 tmp_buf = calloc(p - buffer + 1, 1);
 629                                 strncpy(tmp_buf, buffer, p - buffer );

zend_memrchr 看起来是个和 strrchr 差不多的函数,在字符串里查找字符。第三个参数是字符串的长度。从这里出内存错误,多半是访问越界。这个长度里,p 的来源是 strchr 。如果 buffer 里没有 ‘\n’,又没以 ‘\0’ 结尾就有可能造成返回的 p 不在 buffer 的正常范围内,就可能造成访问越界。但是什么情况下回出现呢?查看 buffer 的来历的时候,看到有这么一行。

 550         buffer_len = vspprintf(&buffer, PG(log_errors_max_len), format, args);

log_errors_max_len 是 php.ini 里关于错误信息长度的选项。于是想到,会不会是那个爆长的 solr 错误信息引发的。

写一个测试代码:

<?php
throw new Exception("long message ".str_repeat('.', 10240));

带着 xdebug 运行一下,果然又出现 Segmentation fault 。

已提交 bug:http://bugs.xdebug.org/view.php?id=885
对应 xdebug 版本 2.2.1