在调试一个用了 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