msgbartop
PHP源码分析,Zend引擎分析,Web相关技术研究,Web技术分享–左手代码 右手诗
msgbarbottom

31 Dec 08 一个低概率的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'];

}
?>

Related Posts:

  • No Related Post

Reader's Comments

  1. |

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

  2. |

    @truemyth, 恩,2年见一次.

  3. |

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

Leave a Comment

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word