我们有一个64位的Web服务器,内存为7GB,PHP在周末运行我们的网站时崩溃,该网站由带有选择性Zend类的Codeigniter提供支持。几乎所有进入我们网站的PHP请求都导致了SIGSEGV。我们运行该网站的同一规范上的其他服务器的数量要少得多。不确定是否相关,我们正在运行APC(PHP 5.3.6附带的版本,我认为它是3.1.3p1),我们发现我们有很多“无法为池分配内存”。在错误日志中。运行APC统计信息我发现缓存已满。
所以我的第一个问题,我认为拥有完整的APC缓存不应该导致SIGSEGV?
这是标题和gdb的PHP 5.3.6,我想出了以下回溯:
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7f9d259007e0 (LWP 6020)] strlen () at ../sysdeps/x86_64/strlen.S:31 31 pcmpeqb (%rdi), %xmm2 (gdb) backtrace #0 strlen () at ../sysdeps/x86_64/strlen.S:31 #1 0x00007f9d1e14e274 in xbuf_format_converter (xbuf=0x7fffa8560f10, fmt=0x7f9d1e26d0df "s, %s%s given, called in %s on line %d and defined", ap=0x7fffa8560fb0) at /usr/src/debug/php-5.3.6/main/spprintf.c:574 #2 0x00007f9d1e14f164 in vspprintf (pbuf=0x7f9d270327d8, max_len=0, format=, ap=) at /usr/src/debug/php-5.3.6/main/spprintf.c:797 #3 0x00007f9d1e19b56f in zend_error (type=4096, format=0x7f9d1e26d0b8 "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined") at /usr/src/debug/php-5.3.6/Zend/zend.c:1051 #4 0x00007f9d1e1eac56 in zend_verify_arg_error (execute_data=0x7f9d257e88f8) at /usr/src/debug/php-5.3.6/Zend/zend_execute.c:471 #5 zend_verify_arg_type (execute_data=0x7f9d257e88f8) at /usr/src/debug/php-5.3.6/Zend/zend_execute.c:505 #6 ZEND_RECV_SPEC_HANDLER (execute_data=0x7f9d257e88f8) at /usr/src/debug/php-5.3.6/Zend/zend_vm_execute.h:449 #7 0x00007f9d1e1c0e30 in execute (op_array=0x7f9d26ffe998) at /usr/src/debug/php-5.3.6/Zend/zend_vm_execute.h:107 #8 0x00007f9d1e19b0fd in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /usr/src/debug/php-5.3.6/Zend/zend.c:1194 #9 0x00007f9d1e1487c8 in php_execute_script (primary_file=0x7fffa8563640) at /usr/src/debug/php-5.3.6/main/main.c:2268 #10 0x00007f9d1e2246a5 in php_handler (r=0x7f9d26dbc8c0) at /usr/src/debug/php-5.3.6/sapi/apache2handler/sapi_apache2.c:669 #11 0x00007f9d2593d8b0 in ap_run_handler (r=0x7f9d26dbc8c0) at /usr/src/debug/httpd-2.2.16/server/config.c:158 #12 0x00007f9d2594116e in ap_invoke_handler (r=0x7f9d26dbc8c0) at /usr/src/debug/httpd-2.2.16/server/config.c:376 #13 0x00007f9d2594c5fc in ap_internal_redirect (new_uri=, r=) at /usr/src/debug/httpd-2.2.16/modules/http/http_request.c:502 #14 0x00007f9d1f3637a5 in handler_redirect (r=0x7f9d26dcad38) at /usr/src/debug/httpd-2.2.16/modules/mappers/mod_rewrite.c:4831 #15 0x00007f9d2593d8b0 in ap_run_handler (r=0x7f9d26dcad38) at /usr/src/debug/httpd-2.2.16/server/config.c:158 #16 0x00007f9d2594116e in ap_invoke_handler (r=0x7f9d26dcad38) at /usr/src/debug/httpd-2.2.16/server/config.c:376 #17 0x00007f9d2594c7c0 in ap_process_request (r=0x7f9d26dcad38) at /usr/src/debug/httpd-2.2.16/modules/http/http_request.c:282 #18 0x00007f9d25949698 in ap_process_http_connection (c=0x7f9d26dabf78) at /usr/src/debug/httpd-2.2.16/modules/http/http_core.c:190 #19 0x00007f9d259453c8 in ap_run_process_connection (c=0x7f9d26dabf78) at /usr/src/debug/httpd-2.2.16/server/connection.c:43 #20 0x00007f9d259510b7 in child_main (child_num_arg=) at /usr/src/debug/httpd-2.2.16/server/mpm/prefork/prefork.c:662 #21 0x00007f9d259513ca in make_child (s=0x7f9d268a8860, slot=17) at /usr/src/debug/httpd-2.2.16/server/mpm/prefork/prefork.c:758 #22 0x00007f9d2595204c in perform_idle_server_maintenance (_pconf=, plog=, s=) at /usr/src/debug/httpd-2.2.16/server/mpm/prefork/prefork.c:893 #23 ap_mpm_run (_pconf=, plog=, s=) at /usr/src/debug/httpd-2.2.16/server/mpm/prefork/prefork.c:1097 #24 0x00007f9d25929840 in main (argc=1, argv=0x7fffa8563c88) at /usr/src/debug/httpd-2.2.16/server/main.c:740
使用一些简单的gdb,我发现执行似乎已经到达Zend_Locale :: _ prepareLocale(),显然当PHP试图输出错误消息时,一些错误的指针导致了SIGSEGV:
(gdb) frame 9 #9 0x00007f9d1e1487c8 in php_execute_script (primary_file=0x7fffa8563640) at /usr/src/debug/php-5.3.6/main/main.c:2268 2268 retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS); (gdb) p *primary_file $1 = {type = ZEND_HANDLE_FILENAME, filename = 0x7f9d26dcd2d0 "/mnt/goserver/goanimate.com/index.php", opened_path = 0x0, handle = {fd = 646922536, fp = 0x7f9d268f4128, stream = {handle = 0x7f9d268f4128, isatty = 0, mmap = {len = 140312938585584, pos = 140312938463096, map = 0x7f9d26dca068, buf = 0x7f9d26dabff8 "\310\307\332&\235\177", old_handle = 0x7f9d25948971, old_closer = 0}, reader = 0xc, fsizer = 0x7f9d26dc3840, closer = 0x7f9d26dca078}}, free_filename = 0 '\000'} (gdb) frame 7 #7 0x00007f9d1e1c0e30 in execute (op_array=0x7f9d27000c40) at /usr/src/debug/php-5.3.6/Zend/zend_vm_execute.h:107 107 if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0) { (gdb) p *op_array $2 = {type = 2 '\002', function_name = 0x7f9d0ef9aec0 "_prepareLocale", scope = 0x7f9d26ffd228, fn_flags = 1025, prototype = 0x0, num_args = 2, required_num_args = 1, arg_info = 0x7f9d0ef9ae68, pass_rest_by_reference = 0 '\000', return_reference = 0 '\000', done_pass_two = 1 '\001', refcount = 0x7f9d27000d38, opcodes = 0x7f9d0efad760, last = 161, size = 161, vars = 0x7f9d0efb2540, last_var = 12, size_var = 16, T = 94, brk_cont_array = 0x7f9d0efb2530, last_brk_cont = 1, current_brk_cont = -1, try_catch_array = 0x0, last_try_catch = 0, static_variables = 0x0, start_op = 0x0, backpatch_count = 0, this_var = 4294967295, filename = 0x7f9d0ef9aed0 "/mnt/goserver/gslib/include/Zend/Locale.php", line_start = 1003, line_end = 1069, doc_comment = 0x7f9d0ef9af08 "/**\n * Internal function, returns a single locale on detection\n *\n * @param string|Zend_Locale $locale (Optional) Locale to work on\n * @param boolean", ' ' , "$strict (Optional) St"..., doc_comment_len = 362, early_binding = 4294967295, reserved = {0x1, 0x0, 0x0, 0x0}} (gdb) p op_array->arg_info $3 = (zend_arg_info *) 0x7f9d0ef9ae68 (gdb) p *(op_array->arg_info) $4 = {name = 0x7f9d0ef9c3b0 "locale", name_len = 6, class_name = 0xffffffff , class_name_len = 0, array_type_hint = 0 '\000', allow_null = 1 '\001', pass_by_reference = 0 '\000', return_reference = 0 '\000', required_num_args = 0} (gdb) frame 2 #2 0x00007f9d1e14f164 in vspprintf (pbuf=0x7f9d27034a98, max_len=0, format=, ap=) at /usr/src/debug/php-5.3.6/main/spprintf.c:797 797 xbuf_format_converter(&xbuf, format, ap); (gdb) frame 1 #1 0x00007f9d1e14e274 in xbuf_format_converter (xbuf=0x7fffa8560f10, fmt=0x7f9d1e26d0df "s, %s%s given, called in %s on line %d and defined", ap=0x7fffa8560fb0) at /usr/src/debug/php-5.3.6/main/spprintf.c:574 574 s_len = strlen(s); (gdb) p s $7 = 0xffffffff
我正在考虑在Zend引擎代码中没有注意到的mallocs等失败,但我不太了解Zend内部确认它。有人有这方面的线索吗?感谢。
答案 0 :(得分:0)
我不是C程序员,不了解PHP解释器/ Zend引擎背后的源代码。然而,我遵循Zend_Locale :: _ prepareLocale()方法,并在您指定的调试数据中,我正在考虑调用strlen()导致溢出。我在想:
C中的strlen()调用是从与字符串相关的PHP函数调用中转换而来的。在上面提到的Zend_Locale方法中,我看到了这些可能相关的PHP函数:explode(),strstr(),strlen()。
通过检查Zend_Local :: _ prepareLocale(),您会发现传递给字符串函数的数据是 $ local 变量。由于此语言环境是由不同的资源(环境变量,用户浏览器指定的数据等)构建的,因此该值可能导致内存故障。如果您可以找出导致它的PHP程序的状态,那么调试可能会更容易。可能正在编辑Zend_Locale的源代码并在某些行上打印 $ locale 变量以进行逐行调试。