Pukiwikiのページ表示時にapacheのプロセスがSegmentation faultする

Pukiwikiで突如、ページが表示されなくなったと思ったらapacheのプロセスごと落ちていた。PHPのエラーログは出ていない。apacheのエラーログには単に以下のようなログだけ。

child pid 1118 exit signal Segmentation fault (11)

レアケースだと思うが、結論としてはPukiwikiのソースをいじって解決。

PHP – Segmentation fault 原因不明のエラーをデバッグする方法 | 海は海、風は風 dozo.rgr.jp
ここを参考にまずは原因究明。

gdbでrunすると

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1208199488 (LWP 585)]
0x0049b16f in pcre_dfa_exec () from /lib/libpcre.so.0

で止まった。btすると大量に行が出力されるが、途中、php_pcre_replaceなどとあるのでpreg_replace系に何やら問題があるらしい。

大方長過ぎる文字列を渡して正規表現がおかしくなっているんだろう、と思い、Pukiwikiのコード中に適当にdie("hoge")を入れて、セグフォする箇所を特定。

convert_html内で呼び出しているlib/make_link.phpのclass InlineConverterのconvertメソッドで使っているpreg_replace_callbackが原因と判明。

$string = preg_replace_callback('/' . $this->pattern . '/x',
       array(& $this, 'replace'), $string);

ここで渡している$this->patternはずいぶんと複雑な正規表現(文字数にして2496文字!)で、$stringの方もそのときは35000文字もあったので、こりゃぁ落ちるな、という気がした。

とりあえず if (strlen($string) < 35000) を加えて無事表示できた。そもそもの原因としてはプラグインの#urlbookmarkがタイトル抽出に失敗していた。35000文字以上もタイトルとしてHTMLから取ってきて、そこにリンクを張ろうとして落ちたのだった。

plugin/urlbookmark.inc.phpのfunction plugin_urlbookmark_get_titleが
preg_match('/<title(\s+[^>]+)*>(.*)<\/title\s*>/i', $buf, $tmpary);

と貪欲になっていたので修正したらタイトル抽出の失敗も直った。
preg_match('/<title(\s+[^>]+)*>(.*?)<\/title\s*>/i', $buf, $tmpary);

preg_replace_callbackのバグの原因まで追究したいところだが、、うーん。

This entry was posted in いじる. Bookmark the permalink. Both comments and trackbacks are currently closed.

Page optimized by WP Minify WordPress Plugin