PHPがsegmentation faultで死ぬ原因を追跡する
発端
WordPressで構築されたサイトで 502 Proxy Error
が出る、という問題が発生した。
[LB] -> [Reverse proxy] -> [Webサーバ]
という構成のため、ユーザへ返るステータスコードは Reverse proxy
が吐いてる。
ここが 502 Proxy Error
となるのは、プロキシした先の Webサーバ
でhttpdプロセスが異常終了してしまっている事が原因だった。
※ちなみに今回PHPのセグフォでhttpdが死んでいるのは、dsoだったため。httpdから生えたcgiだった場合、cgiのセグフォをhttpdが検知できるので、恐らく500エラーを返すことになる
なぜ異常終了しているかを調べた(未解決)
- httpdのエラーログを見ると、プロセスがセグフォで死んでいることがわかる。
[Wed Nov 30 11:53:51.240210 2016] [core:notice] [pid 16547] AH00052: child pid 18079 exit signal Segmentation fault (11)
- straceでセグフォで死ぬプログラムをみてみると
brk
システムコールを呼び続けて最後に死んでた
brk(0x5631000) = 0x5631000 brk(0x5671000) = 0x5671000 brk(0x56b1000) = 0x56b1000 brk(0x56f1000) = 0x56f1000 brk(0x5731000) = 0x5731000 brk(0x5771000) = 0x5771000 brk(0x57b1000) = 0x57b1000 brk(0x57f1000) = 0x57f1000 brk(0x5831000) = 0x5831000 brk(0x5871000) = 0x5871000 brk(0x58b1000) = 0x58b1000 --- SIGSEGV (Segmentation fault) @ 0 (0) --- +++ killed by SIGSEGV +++
brkシステムコール直前 wp-content/cache/object/
とキャッシュを触っており、キャッシュ関連のプラグインが怪しいと目星がついたので、試しにそのプラグインを無効化すると、本問題は発生しなくなった。
プラグイン無効化で終わり、でもいいが、なぜセグフォするのかもう少し調査
- 次にcore dumpを吐かせた
# coreファイルのサイズ制限を外す $ ulimit -c unlimited # 確認 $ ulimit -a | grep core # 問題のコードを実行する # カレントディレクトリにcoreがはかれる $ ls -l core.19380 # fileコマンドで何のプログラムでセグフォしたcoreかみれる $ file core.19380 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, from '/usr/local/php/bin/php-cgi sample.php' # gdbで解析 $ gdb /usr/local/php/bin/php-cgi -c core.19380 (略) Core was generated by `/usr/local/php/bin/php-cgi sample.php'. Program terminated with signal 11, Segmentation fault. #0 zend_parse_arg (arg_num=1, arg=0x5e4a6b8, va=0x7ffdbf6cd110, spec=0x7ffdbf6cd0c8, quiet=0, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_API.c:686 686 /tmp/php-build/source/5.6.21/Zend/zend_API.c: そのようなファイルやディレクトリはありません. in /tmp/php-build/source/5.6.21/Zend/zend_API.c (略) (gdb) bt #0 zend_parse_arg (arg_num=1, arg=0x5e4a6b8, va=0x7ffdbf6cd110, spec=0x7ffdbf6cd0c8, quiet=0, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_API.c:686 #1 0x000000000089dec3 in zend_parse_va_args (num_args=<value optimized out>, type_spec=0xa2b863 "s", va=0x7ffdbf6cd110, flags=<value optimized out>, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_API.c:873 #2 0x000000000089e7d6 in zend_parse_parameters (num_args=1, tsrm_ls=0x1b350c0, type_spec=<value optimized out>) at /tmp/php-build/source/5.6.21/Zend/zend_API.c:924 #3 0x00000000008a8464 in zif_defined (ht=<value optimized out>, return_value=0x5dff408, return_value_ptr=<value optimized out>, this_ptr=<value optimized out>, return_value_used=<value optimized out>, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_builtin_functions.c:735 #4 0x000000000091bf93 in zend_do_fcall_common_helper_SPEC (execute_data=<value optimized out>, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:558 #5 0x0000000000909c4b in execute_ex (execute_data=0x5e4a610, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:363 #6 0x000000000091c44e in zend_do_fcall_common_helper_SPEC (execute_data=<value optimized out>, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:592 #7 0x0000000000909c4b in execute_ex (execute_data=0x5e4a3d0, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:363 #8 0x000000000091c44e in zend_do_fcall_common_helper_SPEC (execute_data=<value optimized out>, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:592 #9 0x0000000000909c4b in execute_ex (execute_data=0x5e49b38, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:363 #10 0x000000000091c44e in zend_do_fcall_common_helper_SPEC (execute_data=<value optimized out>, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:592 #11 0x0000000000909c4b in execute_ex (execute_data=0x5e499d0, tsrm_ls=0x1b350c0) at /tmp/php-build/source/5.6.21/Zend/zend_vm_execute.h:363 (略)
Zend/zend_vm_execute.h:363行目
と Zend/zend_vm_execute.h:592行目
が無限につづいていた。
なんでこうなるのかよくわかってない。Zendのバグなんじゃないの?とか思って眺めてた。
また、上記の問題は thread safe版
の場合。試しに同じconfigureオプションで作った non thread safe版
を使用して同じプログラムを実行させると、セグフォはおきなかった。
その代わりに brk
システムコールを無限に実行し続けて memory_limit
の値に引っかかってた。
試しに1GBほど割り当てても同様に全て食いつぶしてメモリ不足になってたので、やっぱりZendのバグなんじゃないの?とか思ってる。
ここからどうすれば根本的な原因(もしあるならバグの箇所)までたどり着けるのか、調べ方がわからない。勉強しようと思った