Node.jsでセグメンテーションフォルトが発生したので調査した

Node.js v4.3をv4.8にアップデートしたところsegmentation faultが多発するようになった。

/var/log/messages を見ると以下のようなログが残っている

May 15 08:51:32 hostname-hoge001 kernel: node[11262]: segfault at a764a503788 ip 0000000000aecd71 sp 00007ffd5a48b380 error 4 in node[400000+1376000]

error 4、「ユーザーモードでの読み込み時にページが見つからなかった」らしい。過去にメモリ不足で発生したことがあったが、今回はメモリは十分足りている。全く原因がわからないのでコアダンプを取って調べる事にした。

コアを吐くように ulimit -c unlimited を呼び出してからNode.jsプロセスを起動するように起動スクリプトを修正。

本番環境にリリースし、プロセスが落ちてコアを吐くのを待つ。3日ほど放置してコアダンプを収穫。ちなみにこのシステムはNode.jsプロセスの1つや2つが落ちても問題ない設計になっている。

(gdb) bt
#0  0x0000000000aecd71 in v8::internal::MarkCompactCollector::ProcessWeakCollections() ()
#1  0x0000000000af50d4 in v8::internal::MarkCompactCollector::MarkLiveObjects() ()
#2  0x0000000000af5b71 in v8::internal::MarkCompactCollector::CollectGarbage() ()
#3  0x0000000000aaccf0 in v8::internal::Heap::MarkCompact() ()
#4  0x0000000000ac4718 in v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) ()
#5  0x0000000000ac4cb9 in v8::internal::Heap::CollectGarbage(v8::internal::GarbageCollector, char const*, char const*, v8::GCCallbackFlags) ()
#6  0x0000000000ac56c1 in v8::internal::Heap::HandleGCRequest() ()
#7  0x0000000000a6131c in v8::internal::StackGuard::HandleInterrupts() ()
#8  0x0000000000c96f8b in v8::internal::Runtime_StackGuard(int, v8::internal::Object**, v8::internal::Isolate*) ()
#9  0x0000065d13a06355 in ?? ()
#10 0x0000000600000007 in ?? ()
#11 0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000c7a38e in v8::internal::Runtime_WeakCollectionGet(int, v8::internal::Object**, v8::internal::Isolate*) ()
#1  0x0000329d23a0963b in ?? ()
#2  0x0000329d23a09581 in ?? ()
#3  0x00007ffd20be0830 in ?? ()
-- 省略 --
#78 0x00000000030b7f60 in ?? ()
#79 0x00000000030b5fc0 in ?? ()
#80 0x00007ffd20be0b90 in ?? ()
#81 0x0000000000b9227f in v8::internal::KeyedLoadIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*) ()

デバッグビルドではないので行番号は取れないが、Weak Collectionの処理でエラーになっている事がわかった。確かにアプリケーションのソースコードを見るとWeakMapを使っている箇所がある。

さて、次はV8のソースを確認。まずNode.jsに組み込まれたV8のバージョンを調べる。

$ node -p process.versions.v8
4.5.103.45

Node.js v4.3のV8のバージョンは4.5.103.35、v4.8は4.5.103.45である。しかしgitリポジトリに4.5.103.45というタグがないため、V8にどのような変更が加えられたのか分からない。まぁ、変更点が分かったところで弱参照オブジェクトのGCなどコミッタ級の知識がなければ対処不能レベルだろうから、V8の変更点を追うのは一旦あきらめる。

一応、ここ https://nodejs.org/download/release/v4.8.0/ のtarballには V8のソースも付いているので調べることはできる。

Node.jsを6系にアップデートすれば直りそうな気がするが、今は6系で動作検証する余裕がないのでWeakMapを使わないようにしてリリースした。さて直るかな?