Ruby アプリのセグメンテーション違反の修正
最終更新日 2023年03月20日(月)
無効なメモリコマンドをソフトウェアから発行しようとすると、セグメンテーション違反が発生することがあります。たとえば、すでに解放済みのメモリをプログラムが解放しようとしたり (二重解放)、未割り当てのメモリの位置にアクセスしたりする (無効なメモリアクセス) 場合があります。Ruby コードを実行しているとき、セグメンテーション違反をトリガーする方法は主に 2 つあります。
- Ruby 仮想マシンでのセグメンテーション違反
- ネイティブ拡張機能ライブラリでのセグメンテーション違反
次の出力は、Ruby アプリケーションログ内でセグメンテーション違反がどのように表示されるかを示す例です。
2016-05-10T03:04:11.572681+00:00 app[web.1]: -- Control frame information -----------------------------------------------
2016-05-10T03:04:11.582158+00:00 app[web.1]: 975 /app/vendor/bundle/ruby/2.2.0/gems/sass-3.4.22/lib/sass/supports.rb
2016-05-10T03:04:11.572682+00:00 app[web.1]: c:0001 p:---- s:0002 e:000001 TOP [FINISH]
2016-05-10T03:04:11.582159+00:00 app[web.1]: 976 /app/vendor/bundle/ruby/2.2.0/gems/sass-3.4.22/lib/sass/engine.rb
2016-05-10T03:04:11.582160+00:00 app[web.1]: 977 /app/vendor/bundle/ruby/2.2.0/gems/sass-3.4.22/lib/sass/railtie.rb
2016-05-10T03:04:11.572683+00:00 app[web.1]:
2016-05-10T03:04:11.582162+00:00 app[web.1]: 978 /app/vendor/bundle/ruby/2.2.0/gems/sass-3.4.22/lib/sass/features.rb
2016-05-10T03:04:11.582162+00:00 app[web.1]: 979 /app/vendor/bundle/ruby/2.2.0/gems/sass-3.4.22/lib/sass.rb
2016-05-10T03:04:11.572684+00:00 app[web.1]:
2016-05-10T03:04:11.582163+00:00 app[web.1]: 980 /app/vendor/bundle/ruby/2.2.0/gems/sprockets-3.6.0/lib/sprockets/sass_functions.rb
2016-05-10T03:04:11.572684+00:00 app[web.1]: -- C level backtrace information -------------------------------------------
2016-05-10T03:04:11.580053+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(rb_vm_bugreport+0x51f) [0x7fc9c783dfbf] vm_dump.c:693
2016-05-10T03:04:11.580095+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(rb_bug+0xca) [0x7fc9c78af95a] error.c:409
2016-05-10T03:04:11.580156+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(newobj_of+0x1be) [0x7fc9c770932e] gc.c:1635
2016-05-10T03:04:11.580241+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(rb_str_dup+0x1b) [0x7fc9c77c3fcb] string.c:552
2016-05-10T03:04:11.582165+00:00 app[web.1]: 981 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails/helpers.rb
2016-05-10T03:04:11.580402+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(rb_class_path+0x83) [0x7fc9c77fea03] variable.c:259
2016-05-10T03:04:11.580460+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(thread_start_func_2+0x1e1) [0x7fc9c784c5c1] thread.c:2717
2016-05-10T03:04:11.580543+00:00 app[web.1]: /app/vendor/ruby-2.2.2/bin/ruby(thread_start_func_1+0xbb) [0x7fc9c784d0eb] thread_pthread.c:846
2016-05-10T03:04:11.580604+00:00 app[web.1]: /lib/x86_64-linux-gnu/libpthread.so.0(start_thread+0xc2) [0x7fc9c7285182]
2016-05-10T03:04:11.580654+00:00 app[web.1]: /lib/x86_64-linux-gnu/libc.so.6(__clone+0x6d) [0x7fc9c686f47d]
Ruby 仮想マシンでのセグメンテーション違反
C で記述された Ruby 仮想マシン (VM) でセグメンテーション違反が発生する可能性がありますが、これは非常にまれです。Ruby 2 以降に対応した VM は高い安定性を保っており、純粋な Ruby コードを記述してセグメンテーション違反が発生することはまれです。たいていの場合、セグメンテーション違反は C や C++ などのメモリ安全性のない言語を使用したネイティブ拡張機能によって発生します。
Ruby 言語は、ユーザーがメモリを手動で管理しないため、メモリ安全性があるとみなされています。代わりに、Ruby ではガベージコレクターが使用されます。純粋な Ruby コード (ネイティブ拡張機能のない) によってトリガーされるすべてのセグメンテーション違反は、Ruby コアによってバグとみなされます。
Ruby はメモリ安全性のある言語ですが、メモリ安全性のない言語で実装されています。Ruby のほとんどすべての内部機能およびガベージコレクターは、メモリ安全性のない C で記述されています。しかし、純粋な Ruby コードでトリガーされる可能性があるセグメンテーション違反が見つかることはまれです。
アプリケーションのセグメンテーション違反が発生した場合、最初に最新の Ruby バージョンのパッチリリースを使用していることを確認します。Ruby の内部機能のバグが原因である場合、問題は報告されていて修正済みである可能性があります。そのような場合、アップグレードすると問題が解決することがあります。
アプリケーションが最新の Ruby バージョンであることを確認した後もセグメンテーション違反が続く場合、以下の説明に従って、問題の原因になっているネイティブ拡張機能の可能性を除外してください。ネイティブ拡張機能のない、問題の最小限の再現を作成できる場合、Ruby コアのバグトラッカーに報告してください。
ネイティブ拡張機能でのセグメンテーション違反
rubygems.org に由来するほとんどすべてのライブラリは Ruby で記述されています。一部のライブラリは他の言語で記述されており、Ruby で提供された外部関数インターフェース (FFI) または C API を使用して、Ruby コードと対話します。これらの言語がネイティブマシンコードにコンパイルされると、ネイティブ拡張機能と呼ばれます。ほとんどすべてのセグメンテーション違反は、ネイティブ拡張機能を実装するために使用されるメモリ安全性のない言語のエラーに由来します。通常、セグメンテーション違反は C または C++ の拡張機能に由来します。
ネイティブ拡張機能を使用または記述する理由はさまざまです。ヘッダーのインポートや API の使用によって Heroku 上のライブラリを利用したり、パフォーマンスを改善したりするために記述されます。
次のコマンドを使用して、C 拡張機能を含むライブラリを見つけることができます。
$ bundle show --paths | ruby -e "STDIN.each_line {|dep| puts dep.split('/').last if File.directory?(File.join(dep.chomp, 'ext')) }"
bcrypt-3.1.18
bindex-0.8.1
bluecloth-2.2.0
bootsnap-1.13.0
concurrent-ruby-1.1.10
ffi-1.15.4
json-2.6.2
msgpack-1.5.6
nio4r-2.5.8
nokogiri-1.13.8
oj-3.13.21
pg-1.2.3
puma-5.6.5
rb-fsevent-0.11.0
rbtrace-0.4.14
sassc-2.4.0
scout_apm-5.3.1
skylight-5.3.3
stackprof-0.2.17
unf_ext-0.0.7.7
websocket-driver-0.7.5
このサンプル出力は、オープンソースアプリケーションの CodeTriage から生成されたものです。
アプリケーションのネイティブ拡張機能の一覧が得られたら、バージョンをアップグレードしてみて、セグメンテーション違反が報告されてすでに修正されているかどうか確認します。また、Ruby バージョンが最新のパッチリリースにアップグレードされていることを確認してください。
ネイティブ拡張機能および Ruby のバージョンをアップグレードしても解決しない場合、セグメンテーション違反の Ruby バックトレースを使用して詳細を確認できます。短縮した例を以下に示します。
2016-05-10T03:04:11.580659+00:00 app[web.1]: -- Other runtime information -----------------------------------------------
2016-05-10T03:04:11.580659+00:00 app[web.1]:
2016-05-10T03:04:11.580661+00:00 app[web.1]: * Loaded script: puma: cluster worker 1: 27 [app]
2016-05-10T03:04:11.580662+00:00 app[web.1]:
2016-05-10T03:04:11.580663+00:00 app[web.1]: * Loaded features:
2016-05-10T03:04:11.580664+00:00 app[web.1]:
2016-05-10T03:04:11.580667+00:00 app[web.1]: 0 enumerator.so
2016-05-10T03:04:11.580668+00:00 app[web.1]: 1 rational.so
2016-05-10T03:04:11.580668+00:00 app[web.1]: 2 complex.so
2016-05-10T03:04:11.580671+00:00 app[web.1]: 3 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/x86_64-linux/enc/encdb.so
2016-05-10T03:04:11.580671+00:00 app[web.1]: 4 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/x86_64-linux/enc/trans/transdb.so
2016-05-10T03:04:11.580672+00:00 app[web.1]: 5 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/unicode_normalize.rb
2016-05-10T03:04:11.580673+00:00 app[web.1]: 6 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/x86_64-linux/rbconfig.rb
2016-05-10T03:04:11.580675+00:00 app[web.1]: 7 thread.rb
2016-05-10T03:04:11.580676+00:00 app[web.1]: 8 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/x86_64-linux/thread.so
2016-05-10T03:04:11.580676+00:00 app[web.1]: 9 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/rubygems/compatibility.rb
2016-05-10T03:04:11.580677+00:00 app[web.1]: 10 /app/vendor/ruby-2.2.2/lib/ruby/2.2.0/rubygems/defaults.rb
2016-05-10T03:04:11.582166+00:00 app[web.1]: 982 /app/vendor/bundle/ruby/2.2.0/gems/sprockets-3.6.0/lib/sprockets/sass_importer.rb
2016-05-10T03:04:11.582166+00:00 app[web.1]: 983 /app/vendor/bundle/ruby/2.2.0/gems/tilt-2.0.2/lib/tilt/mapping.rb
2016-05-10T03:04:11.582168+00:00 app[web.1]: 984 /app/vendor/bundle/ruby/2.2.0/gems/tilt-2.0.2/lib/tilt/template.rb
2016-05-10T03:04:11.582169+00:00 app[web.1]: 985 /app/vendor/bundle/ruby/2.2.0/gems/tilt-2.0.2/lib/tilt.rb
2016-05-10T03:04:11.582169+00:00 app[web.1]: 986 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails/importer.rb
2016-05-10T03:04:11.582172+00:00 app[web.1]: 987 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails/cache_store.rb
2016-05-10T03:04:11.582172+00:00 app[web.1]: 988 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails/template.rb
2016-05-10T03:04:11.582173+00:00 app[web.1]: 989 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails/logger.rb
2016-05-10T03:04:11.582175+00:00 app[web.1]: 990 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails/railtie.rb
2016-05-10T03:04:11.582175+00:00 app[web.1]: 991 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass/rails.rb
2016-05-10T03:04:11.582176+00:00 app[web.1]: 992 /app/vendor/bundle/ruby/2.2.0/gems/sass-rails-5.0.4/lib/sass-rails.rb
2016-05-10T03:04:11.582178+00:00 app[web.1]: 993 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/version.rb
2016-05-10T03:04:11.582178+00:00 app[web.1]: 994 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/module.rb
2016-05-10T03:04:11.582179+00:00 app[web.1]: 995 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/encoding.rb
2016-05-10T03:04:11.582182+00:00 app[web.1]: 996 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/runtime.rb
2016-05-10T03:04:11.582182+00:00 app[web.1]: 997 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/disabled_runtime.rb
2016-05-10T03:04:11.582183+00:00 app[web.1]: 998 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/duktape_runtime.rb
2016-05-10T03:04:11.582185+00:00 app[web.1]: 999 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/external_runtime.rb
2016-05-10T03:04:11.582186+00:00 app[web.1]: 1000 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/ruby_racer_runtime.rb
2016-05-10T03:04:11.582187+00:00 app[web.1]: 1001 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/ruby_rhino_runtime.rb
2016-05-10T03:04:11.582187+00:00 app[web.1]: 1002 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs/runtimes.rb
2016-05-10T03:04:11.582190+00:00 app[web.1]: 1003 /app/vendor/bundle/ruby/2.2.0/gems/execjs-2.6.0/lib/execjs.rb
2016-05-10T03:04:11.582190+00:00 app[web.1]: 1004 /app/vendor/bundle/ruby/2.2.0/gems/uglifier-3.0.0/lib/uglifier/version.rb
2016-05-10T03:04:11.582191+00:00 app[web.1]: 1005 /app/vendor/bundle/ruby/2.2.0/gems/uglifier-3.0.0/lib/uglifier.rb
2016-05-10T03:04:11.582194+00:00 app[web.1]: 1006 /app/vendor/bundle/ruby/2.2.0/gems/coffee-script-source-1.10.0/lib/coffee_script/source.rb
2016-05-10T03:04:11.582194+00:00 app[web.1]: 1007 /app/vendor/bundle/ruby/2.2.0/gems/coffee-script-2.4.1/lib/coffee_script.rb
さかのぼって作業し、バックトレースを使用して原因の特定に努めます。バックトレース内の gem 名がシステム上の gem と異なる場合があることにしてください。この場合、unf_ext
gem が、たとえば unf-<version>
として表示されます。
2016-05-10T03:04:11.590668+00:00 app[web.1]: 1346 /app/vendor/bundle/ruby/2.2.0/gems/unf-0.1.4/lib/unf/version.rb
2016-05-10T03:04:11.581498+00:00 app[web.1]: 517 /app/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/core_ext/string/access.rb
2016-05-10T03:04:11.590669+00:00 app[web.1]: 1347 /app/vendor/bundle/ruby/2.2.0/gems/unf-0.1.4/lib/unf.rb
gem がセグメンテーション違反の原因であると判断した場合は、gem の保守担当に問題を報告してください。セグメンテーション違反のエラー出力全体を提供し、可能であれば常に、セグメンテーション違反を再現する小さなサンプルアプリケーションを含めてください。
“Gemfile の解析中にエラーが発生しました” セグメンテーション違反
環境変数 RUBY_THREAD_VM_STACK_SIZE
と Ruby buildpack の間の対話によってセグメンテーション違反が発生することがあります。セグメンテーション違反は次のようになります。
-----> Compiling Ruby/Rails
!
! There was an error parsing your Gemfile, we cannot continue
! /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/vendor/ruby/heroku-20/lib/ruby/3.0.0/x86_64-linux/enc/encdb.so: [BUG] Segmentation fault at 0x0000000000000018
! ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-linux]
!
! -- Control frame information -----------------------------------------------
! c:0002 p:-11861427355948 s:0006 e:000005 TOP [FINISH]
! c:0001 p:0000 s:0003 E:001870 (none) [FINISH]
エラーメッセージが There was an error parsing your Gemfile, we cannot continue
であることに注意してください。セグメンテーション違反の場所は encdb.so
の中です。また、この例外が buildpack によって Bundler バージョンが特定された後、Ruby バージョンが特定される前に発生することにも注意してください。
このセグメンテーション違反が発生する場合は、次の環境設定をアプリケーションから削除します。
$ heroku config:unset RUBY_THREAD_VM_STACK_SIZE
この例外は、Ruby buildpack が、自身で実行するバージョンの Ruby を使用するために発生します。2022 年 2 月 24 日に、Heroku のエンジニアは、Ruby buildpack のバージョンを 2.x から 3.x にアップグレードしました。このバージョンの Ruby (3.x+) では、以前には発生しなかった RUBY_THREAD_VM_STACK_SIZE
内の値でセグメンテーション違反が発生します。解決策として、この環境変数を設定から削除します。