·天新网首页·加入收藏·设为首页·网站导航
数码笔记本手机摄像机相机MP3MP4GPS
硬件台式机网络服务器主板CPU硬盘显卡
办公投影打印传真
家电电视影院空调
游戏网游单机动漫
汽车新车购车试驾
下载驱动源码
学院开发设计
考试公务员高考考研
业界互联网通信探索
您现在的位置:天新网 > 软件开发 > Web开发 > PHP开发
php打印warning日志引发的core追查
http://www.21tx.com 2012年09月06日

1 2 下一页

春节期间线上出了两个PHP-CGI的core,具体追查过程如下:

一、 Core信息

file core.xxx

bug.php-cgi.3611.1296586902: ELF 64-bit LSB core file AMD x86-64, version 1 (SYSV), SVR4-style, from ‘php-cgi’

gdb  ~/php5/bin/php-cgi  core.xxx


Core was generated by `~/php5/bin/php-cgi –fpm –fpm-config ~/php5/etc/php-fpm.co’.

Program terminated with signal 4, Illegal instruction.

(gdb) bt

#0  0×0000000001000707 in ?? ()

#1  0×00000000006b1402 in zend_hash_destroy (ht=0×7fbffff4f8)

at ~/self/xxx/soft/source/src/php/php-5.2.8/Zend/zend_hash.c:526

#2  0×0000000000732b2e in fcgi_close (req=0×7fbfffd4c0, force=0, destroy=Variable “destroy” is not available.

)

at ~/self/xxx/soft/source/src/php/php-5.2.8/SAPi/cgi/fastcgi.c:894

#3  0×0000000000732d24 in fcgi_finish_request (req=0×7fbfffd4c0)

at ~/self/xxx/soft/source/src/php/php-5.2.8/sapi/cgi/fastcgi.c:1248

#4  0×0000000000732d49 in fcgi_accept_request (req=0×7fbfffd4c0)

at ~/self/xxx/soft/source/src/php/php-5.2.8/sapi/cgi/fastcgi.c:944

#5  0×00000000007352b8 in main (argc=4, argv=0×7fbffff698)

at ~/self/xxx/soft/source/src/php/php-5.2.8/sapi/cgi/cgi_main.c:2224

根据堆栈可以看出core发生在php-fpm在accept一个新请求时,在对上一个请求(请求异常终止?)进行资源释放时core掉的,线上的php访问模式是apache+fastcgi+php的模式。一层层堆栈往下看:

1)         f 0

已经被写坏了,没有什么有用信息

2)         f 1

打印zend_hash_destroy函数的参数

(gdb) p *ht

$5 = {nTableSize = 16779009, nTableMask = 0, nNumOfElements = 16779009, nNextFreeElement = 16779009,

pInternalPointer = 0×1000701, pListHead = 0×1000701, pListTail = 0×1000701, arBuckets = 0×1000701,

pDestructor = 0×1000701, persistent = 1 ‘01′, nApplyCount = 7 ‘a’, bApplyProtection = 0 ‘′}

PHP HashTbale的数据结构可以上网上搜一下,有很多介绍。这个hashtable已经被写坏了,各个节点指向的内存0×1000701,该内存地址在gdb中都是一个不能访问的内存。依然没有什么有用信息。

3)         f 2

查看源码,打印fcgi_close的参数

(gdb) p *req

$6 = {listen_socket = 0, fd = 11, id = 1, keep = 0, in_len = 0, in_pad = 0, out_hdr = 0×0,

out_pos = 0×7fbffffcf8 “0103″,

out_buf = “01a000137鳿00000PHP Warning:  simpleXML_load_string() [<a href='function.simplexml-load-string'>function.simplexml-load-string</a>]: Entity: line 1: parser error : Start tag expected, ‘&lt;’ not found in /hom”…, reserved = “01a00010000000001a0001000000″, env = {nTableSize = 16779009,

nTableMask = 0, nNumOfElements = 16779009, nNextFreeElement = 16779009, pInternalPointer = 0×1000701,

pListHead = 0×1000701, pListTail = 0×1000701, arBuckets = 0×1000701, pDestructor = 0×1000701,

persistent = 1 ‘01′, nApplyCount = 7 ‘a’, bApplyProtection = 0 ‘′}}

(gdb) ptype req

type = struct _fcgi_request {

int listen_socket;

int fd;

int id;

int keep;

int in_len;

int in_pad;

fcgi_header *out_hdr;

unsigned char *out_pos;

unsigned char out_buf[8192];

unsigned char reserved[16];

HashTable env;

} *

调用zend_hash_destroy(&req->env)进行销毁的是req的成员env,这个成员变量是一个hashtable,该hashtable已经被上一个请求写坏了,导致新请求在释放上一个请求时core掉。

req->out_buf数组是php-cgi和apache进行交互的内存缓冲区,简单看了一下,目前out_buf中的内容全部为simple_xml_load…这个PHP WARNNING,类似的错误信息出现在out_buf中的原因是PHP需要通过fastcgi协议打印错误信息到apache的error_log中。req->out_pos指针则指向当前buf末尾。

gdb) p req->out_pos – req->out_buf

$2 = 8312

BUF的末尾位置已经超过了声明的大小8192,所以可以判断后面的env成员变量已经在写out_buf的过程中被写坏了。PHP中有一个重要的全局变量sapi_globals,通过阅读PHP源码得知,新请求的sapi_globals请求数据填充在fcgi_accept_request完成之后的init_request_info函数中,所以当前内存中的sapi_globals仍然是上次请求的残留信息

(gdb) p sapi_globals

从数据中得知导致core的罪魁祸首是线上某个功能的URL

二、 fastcgi源码分析

(1)     源码位置

fastcgi源码位置:php5/sapi/cgi/fastcgi.c

cgi_main源码位置:php5/sapi/cgi/cgi_main.c

(2)     结构体介绍

首先关注一下fcgi_request这个结构体

typedef struct _fcgi_request {

int            listen_socket;

#ifdef _WIN32

int            tcp;

#endif

int            fd;

int            id;

int            keep;

int            in_len;

int            in_pad;

fcgi_header    *out_hdr;

unsigned char  *out_pos;

unsigned char  out_buf[1024*8];

unsigned char  reserved[sizeof(fcgi_end_request_rec)];

HashTable      env;

} fcgi_request;

这个结构体贯穿整个fastcgi请求的处理流程。我们这次需要关注的是out_hdr、out_pos、out_buf这三个成员变量,fastcgi对apache交互的缓存使用out_buf数组,缓存写满后就会flush出去。但不管是正常输出,还是错误信息输出,所有类型的输出全部会缓存到同一段out_buf中,而这些内容输出的时候需要写到不同的fd中。所以fastcgi采用的方法是在每一种输出内容前加入一个8字节的fcgi_header

上一篇: 大话PHP之性能
下一篇: 支持快速迭代的LAMP解决方案 ——贴吧LAMP解决方案

1 2 下一页

关于我们 | 联系我们 | 加入我们 | 广告服务 | 投诉意见 | 网站导航
Copyright © 2000-2011 21tx.com, All Rights Reserved.
晨新科技 版权所有 Created by TXSite.net