注意到PHP崩溃了
没有绝对的方法可以知道PHP崩溃,但可能有迹象。通常,如果您访问始终应该生成输出的页面(例如,具有前导HTML块),并且突然从浏览器中获取“文档不包含数据”,则可能意味着PHP在执行时崩溃了某处。脚本。告诉PHP崩溃的另一种方法是查看Apache错误日志,并查找SEGV(Apache 1.2)或Segmentation Fault(Apache 1.3)。
重要!
要获得具有正确信息的回溯,您必须使用--enable-debug配置PHP!
如果您还没有核心文件:
- 从shell中删除对核心转储大小的任何限制:
tcsh:unlimit coredumpsize
bash / sh:ulimit -c unlimited
- 确保运行PHP的目录或启用PHP的httpd对运行PHP的用户具有写权限。
- 导致PHP崩溃:
PHP CGI:只需使用崩溃的脚本运行php
PHP Apache模块:运行httpd -X,并访问崩溃PHP的脚本
在Linux上获取核心的通用方法
- 设置核心模式(以root身份运行此命令):
echo“<cores dir> /core-%e.%p”> / proc / sys / kernel / core_pattern
确保该目录可由PHP写入
- 设置ulimit(参见上面的方法)。
- 重新启动/重新运行PHP。
之后,系统中崩溃的任何进程(包括PHP)都会将其核心文件保留在您在core_pattern中指定的目录中。
获得核心文件后:
- 运行带有PHP或PHP启用的httpd二进制文件的路径的gdb,以及核心文件的路径。一些例子:
gdb /usr/local/apache/sbin/httpd /usr/local/apache/sbin/core
gdb /home/user/dev/php-snaps/sapi/cli /php/home/user/dev/testing/core
在gdb提示符下,运行:
(gdb) bt
如果您无法获得核心文件:
在gdb下运行httpd -X,例如:
gdb /usr/local/apache/sbin/httpd
(gdb) run -X
然后使用您的Web浏览器访问您的服务器以强制崩溃。您应该会看到一个gdb提示符,并显示一条消息表明发生了崩溃。在此gdb提示符下,键入:
(gdb) bt
或者,从命令行运行
gdb /home/user/dev/php-snaps/sapi/cli/php
(gdb) run /path/to/script.php
(gdb) bt
这应该生成一个回溯,您应该在错误报告中提交,以及您可以向我们提供有关您的设置和违规脚本的任何其他详细信息。
找到导致段错误的函数调用:
您可以使用gdb轻松找到导致段错误的函数调用。首先,您需要一个核心文件或如上所述在gdb下生成段错误。
在PHP中,每个函数都由一个名为execute()的内部函数执行,并有自己的堆栈。 bt命令生成的每一行代表一个函数调用堆栈。通常,在发出bt时会看到几行execute()行。您对最后一个execute()堆栈(即最小帧编号)感兴趣。您可以使用向上,向下或帧命令移动当前工作堆栈。下面是一个示例gdb会话,可用作如何处理segfault的指南。
示例gdb会话
(gdb) bt
#0 0x080ca21b in _efree (ptr=0xbfffdb9b) at zend_alloc.c:240
#1 0x080d691a in _zval_dtor (zvalue=0x8186b94) at zend_variables.c:44
#2 0x080cfab3 in _zval_ptr_dtor (zval_ptr=0xbfffdbfc) at zend_execute_API.c:274
#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605
#4 0x080f1e06 in execute (op_array=0x816c530) at ./zend_execute.c:1638
#5 0x080f1e06 in execute (op_array=0x816c278) at ./zend_execute.c:1638
#6 0x080f1e06 in execute (op_array=0x8166eec) at ./zend_execute.c:1638
#7 0x080d7b93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at zend.c:810
#8 0x0805ea75 in php_execute_script (primary_file=0xbffff650) at main.c:1310
#9 0x0805cdb3 in main (argc=2, argv=0xbffff6fc) at cgi_main.c:753
#10 0x400c91be in __libc_start_main (main=0x805c580
, argc=2, ubp_av=0xbffff6fc,
init=0x805b080 <_init>, fini=0x80f67b4 <_fini>, rtld_fini=0x4000ddd0 <_dl_fini>,
stack_end=0xbffff6ec) at ../sysdeps/generic/libc-start.c:129
(gdb) frame 3
#3 0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605
(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name
$14 = 0x80fa6fa "pg_result_error"
(gdb) print (char *)executor_globals.active_op_array->function_name
$15 = 0x816cfc4 "result_error"
(gdb) print (char *)executor_globals.active_op_array->filename
$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php"
(gdb)
在此会话中,第3帧是最后一次执行()调用。 frame 3命令将当前工作堆栈移动到适当的帧。
print (char *)(executor_globals.function_state_ptr->function)->common.function_name
打印功能名称。在示例gdb会话中,pg_result_error()调用导致segfault。如果您了解内部数据结构,则可以打印任何您喜欢的内部数据。请不要问如何使用gdb或内部数据结构。有关gdb用法的信息,请参阅gdb手册,有关内部数据结构的信息,请参阅PHP源代码。
如果在没有调用任何函数的情况下发生段错误,您可能看不到执行。