ここ一か月近く追い続けた PHP の signal 6 ( SIGABRT ) のバグについて。
先日、日本の PHP-dev ML に投げたところ以下のレスをいただきました。
よくよく見てみたら、apache SAPIでは下記のマクロの中でシグナルをブロックするハンドラに飛ばしていたのですが、 apache2handler SAPIでは何もしていませんでした。なのでそれが原因のような気がします。
…なんだって?
例によって gdb でバックトレース。
Program received signal SIGABRT, Aborted. 0x2836b56f in kill () from /lib/libc.so.6 (gdb) bt #0 0x2836b56f in kill () from /lib/libc.so.6 #1 0x2828d27b in raise () from /usr/lib/libpthread.so.2 #2 0x2836a2ab in abort () from /lib/libc.so.6 : #6 0x2830662c in free () from /lib/libc.so.6 #7 0x28617828 in php_error_cb (type=1, error_filename=0x86b1e38 "/usr/home/hossy/public_html/test.php", error_lineno=391, format=0x2874febc "Maximum execution time of %d second%s exceeded", args=0xbfbf7898 "\n") at /usr/ports/lang/php5/work/php-5.2.9/main/main.c:824 : #10 0x282920d3 in sigaction () from /usr/lib/libpthread.so.2 #11: #15 0x2830662c in free () from /lib/libc.so.6 #16 0x28644cb5 in zend_mm_mem_malloc_free (storage=0x80a1690, ptr=0xa81c000) at /usr/ports/lang/php5/work/php-5.2.9/Zend/zend_alloc.c:276 :
zend_mm_mem_malloc_free() では free() の呼び出しが HANDLE_BLOCK_INTERRUPTIONS() と HANDLE_UNBLOCK_INTERRUPTIONS() に挟まれているので、
シグナルはブロックされて安全…?と、思いきや。
#define HANDLE_BLOCK_INTERRUPTIONS() \ if (zend_block_interruptions) { zend_block_interruptions(); }
ということなので
(gdb) p zend_block_interruptions $1 = (void (*)(void)) 0
あれれー?
(gdb) p sapi_module $2 = {name = 0x28759d5d "apache2handler", pretty_name = 0x28759d6c "Apache 2.0 Handler", : block_interruptions = 0, unblock_interruptions = 0, : (gdb) p apache2_sapi_module $3 = {name = 0x28759d5d "apache2handler", pretty_name = 0x28759d6c "Apache 2.0 Handler", : block_interruptions = 0, unblock_interruptions = 0, :
元々 NULL らしいですね。
というわけで、なんと!ML でパッチを作っていただきました。
http://ml.php.gr.jp/pipermail/php-dev/2009-March/001453.html の添付ファイルがパッチなので、
/usr/ports/lang/php5/files/patch-free-recursive.patch として保存してから、
# portupgrade -f php5-5.2.9
これでパッチ付きでビルドされます。
3日経ちますが特に問題なく動いているようです。
パッチを作って頂いた小泉様、ありがとうございました。