Press "Enter" to skip to content

一个低概率的PHP Core dump

PHP是个脚本语言, 错误定位容易, 编写起来速度较快..但是, 如果遇到了PHP自身的一些问题,那就会让人很恼火.
最近遇到一个很低概率的Core dump(大概是2年才出现一次), 经过和同事一起仔细分析,跟踪,终于找出了原因, 拿出来与大家分享.
先看Core文件展示的堆栈:

(gdb) bt
#0  0x000000302af2e2ed in raise () from /lib64/tls/libc.so.6
#1  0x000000302af2fa3e in abort () from /lib64/tls/libc.so.6
#2  0x000000302af62db1 in __libc_message () from /lib64/tls/libc.so.6
#3  0x000000302af6888e in _int_free () from /lib64/tls/libc.so.6
#4  0x000000302af68bd6 in free () from /lib64/tls/libc.so.6
#5  0x0000002a95bd4a8c in php_error_cb (type=1,
    error_filename=0x2a9755c608 "***********.php", error_lineno=272, format=Variable "format" is not available.
)
    at /home/huixinchen/php-5.2.4/main/main.c:803
#6  0x0000002a95c182ed in zend_error (type=1, format=0x2a95ebee68 "Maximum execution time of %d second%s exceeded")
    at /home/huixinchen/php-5.2.4/Zend/zend.c:976
#7  <signal handler called>
#8  0x000000302af6ac02 in malloc () from /lib64/tls/libc.so.6
#9  0x000000302af6fc92 in strdup () from /lib64/tls/libc.so.6
#10 0x0000002a95bd4720 in php_error_cb (type=8,
    error_filename=0x2a9755c608 "******.php", error_lineno=272, format=Variable "format" is not available.
)
    at /home/huixinchen/php-5.2.4/main/main.c:807

左分析,右分析,结论如下。
在PHP execute limit time 信号来的时候,PHP正在出错处理函数中, 这个时候,事件被响应,再次重入php_error_cb函数, 观察php_error_cb函数:

static void php_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args){
    ....
    if (display) {
        if (PG(last_error_message)) {
            free(PG(last_error_message));
        }
        if (PG(last_error_file)) {
            free(PG(last_error_file));
        }
        PG(last_error_type) = type;
        PG(last_error_message) = strdup(buffer);
        PG(last_error_file) = strdup(error_filename);
        PG(last_error_lineno) = error_lineno;
    }
   ....
}

我们可以看到,在php_error_cb中, 会对上一次的错误文件名进行free操作, 并对当前错误文件名分配内存.
如果, 当php执行到free了旧的错误文件名以后, 响应了事件, 于是分配新的错误文件名内存这一步并没有被执行..
这个时候, 事件响应以后,又再一次进入到了php_error_cb函数, 当再次执行free(PG(last_error_file))的时候, 会导致core dump
另外,发现PHP(*nix下)是通过调用setitimer来实现脚本超时处理的。
具体代码可以grep zend_set_timeout
转一个可以较大概率重现这个Core的脚本(By Lili):

<?php
set_time_limit(1);
while(1) {
    $a = $arr['index_miss'];
    $a = $arr['index_miss'];
    $a = $arr['index_miss'];
    $a = $arr['index_miss'];
    $a = $arr['index_miss'];
    $a = $arr['index_miss'];
}
?>

Be First to Comment

  1. […]   HTTP1.0下HTTP_HOST为空  一个巧妙的分页方法 31 Dec 08 一个低概率的PHP Core dump 21 Feb 09 PHP字符串比较 26 May 09 PHP+Gtk实例(求24点) […]

  2. […] crash的案例:深入理解PHP内存管理之一个低概率Core的分析和一个低概率的PHP Core dump , 在其中, 我说过, 其实PHP在关键操作的时候, […]

  3. 张二
    张二 December 17, 2010

    话说,为啥sudo ulimit -c unlimited 了,还是没有core dump的输入哩……当然,已经–enable-debug过了。

  4. zvaly
    zvaly January 19, 2009

    我想知道你是怎末左分析、右分析的。。。。。。

  5. truemyth
    truemyth December 29, 2008

    这个比较汗…
    这种情况应该很少见吧,都到出错处理了刚好又到limit time了.

    • 雪候鸟
      雪候鸟 December 30, 2008

      @truemyth, 恩,2年见一次.

Comments are closed.