macOS High SierraとRubyのforkの問題

おくればせながら試してみた。

環境はmacOS High Sierra (10.13)。最初の報告にあったpg.gemのためにPostgreSQL 10.0をhomebrewでインストールした。pg.gemのバージョンは0.21.0。

$ gem install pg
Building native extensions.  This could take a while...
Successfully installed pg-0.21.0
Parsing documentation for pg-0.21.0
Installing ri documentation for pg-0.21.0
Done installing documentation for pg after 3 seconds
1 gem installed

$ ruby -r pg -e 'p $".grep(/pg.*bundle/)'
["/Users/akira/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/pg-0.21.0/lib/pg_ext.bundle"]

$ otool -L $(gem which pg_ext)
/Users/akira/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/pg-0.21.0/lib/pg_ext.bundle:
        /usr/local/opt/postgresql/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.10.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
        /usr/local/opt/gmp/lib/libgmp.10.dylib (compatibility version 14.0.0, current version 14.2.0)
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

pg.gemがlibpq.5をリンクしていることを確認して、まずはRuby 2.4.2で試す。

$ ruby -v -e 'Process.waitpid Process.fork { require "pg"; p :OK }'
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-darwin17]
objc[28869]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
objc[28869]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

ついでにRuby 2.2.2。

$ ruby -v -e 'Process.waitpid Process.fork { require "pg"; p :OK }'
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin17]
objc[28781]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
objc[28781]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

検証コードがあった(14009#note-6)ので、そちらも試してみる。

$ ruby -vr fiddle -e 't = ->{ Fiddle.dlopen("/System/Library/Frameworks/Foundation.framework/Foundation") }; Process.waitpid Process.fork(&t)'
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-darwin17]
objc[29520]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
objc[29520]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

$ ruby -vr fiddle -e 't = ->{ Fiddle.dlopen("/System/Library/Frameworks/Foundation.framework/Foundation") }; t.call; Process.waitpid Process.fork(&t)'
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-darwin17]

Ruby 2.2.2でも同様の結果となる。