Rust の勉強中にメモリリーク検出ツール Valgrind を macOS Mojave (10.14.4)にインストールしようとして失敗した

2019年4月から「Rust By Example(実例で学ぶRust)」というサイトを利用して、新たなプログラミング言語としてRustを学んでいる。

 

doc.rust-lang.org

 

現在写経中の15章はRustのメモリ管理をテーマにしており、いよいよRustの大事な部分に入りつつあるが、初っ端から未解決問題につまづいてしまったのでメモしておく。

employment.en-japan.com

 

 

[Rust By ExampleでValgrindを使う]

1ヶ月以上に渡り、ほぼ毎日ちまちまとRust By Exampleの写経を続けている。

github.com

 

おかげで何となくRustの特徴的な文法にも多少は慣れてきた。リターンするときはセミコロン不要というのは最初は戸惑ったが、for文を書く際にカッコがいらないあたりはGo言語にも似ていて、見知った言語のようにも思える。

 

今週取り組み始めた15章の最初のテーマは、RAII(Resource Acquisition Is Initialization)だった。

doc.rust-lang.org

 

いつも通り、章タイトルをファイル名にして写経をしていく。

すると、以下のような指示が出ていた。

Of course, we can double check for memory errors using valgrind

 

Valgrindというツールを使い、メモリーに関するエラーをチェックする必要があるようだ。Wikipediaの記載によれば、Valgrindを利用すると、メモリデバッグメモリリークの検出、スレッドエラーの検出、プロファイリングなどを行うことができるらしい。

 

[HomebrewでValgrindをインストール(失敗)]

早速Rust By Example15章をやっつけてRustの真髄に触れるべく、Valgrindをインストールすることにした。

利用しているOSはmacOS Mojave(バージョン 10.14.4)である。

f:id:kidani_a:20190517020316p:plain

 

まずはhomebrewでのインストールを試してみる。と、以下のようなエラーが出てうまくいかない。

 brew install valgrind
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> New Formulae
(中略)
==> Updated Formulae
(中略)
==> Deleted Formulae
(中略)

valgrind: This formula either does not compile or function as expected on macOS
versions newer than High Sierra due to an upstream incompatibility.
Error: An unsatisfied requirement failed this build.

 

慌てて公式サイトをよく読むと、次のようにmacOS Mojave(バージョン 10.14.4)は未対応である旨が書かれていた。

It runs on the following platforms: X86/Linux, AMD64/Linux,(中略), X86/Darwin and AMD64/Darwin (Mac OS X 10.12).

 

[パッチ適用済ブランチを利用(失敗)]

何とかならないかと思い、「mojave valgrind」でググると、次のページにたどり着くことができた。rather painfulと書かれており、手順はやや面倒そうだが、一応MojaveにもValgrindをインストールできそうに見える。

stackoverflow.com

 

回答の指示に従って手を動かしていく。まずはフォークされたリポジトリをクローンする。

 git clone https://github.com/Echelon9/valgrind.git
Cloning into 'valgrind'...
remote: Enumerating objects: 495, done.
remote: Counting objects: 100% (495/495), done.
remote: Compressing objects: 100% (280/280), done.
remote: Total 124654 (delta 268), reused 329 (delta 213), pack-reused 124159
Receiving objects: 100% (124654/124654), 44.01 MiB | 3.44 MiB/s, done.
Resolving deltas: 100% (94992/94992), done.
Checking out files: 100% (5962/5962), done.

 

次に、パッチが適用されているブランチをチェックアウトする。

$ cd valgrind
$ git checkout feature/v3.14/macos-mojave-support-v2
Branch 'feature/v3.14/macos-mojave-support-v2' set up to track remote branch 'feature/v3.14/macos-mojave-support-v2' from 'origin'.
Switched to a new branch 'feature/v3.14/macos-mojave-support-v2'

 

./autogen.shを実行する。

$ ./autogen.sh
running: aclocal
running: autoheader
running: automake -a
configure.ac:30: installing './compile'
configure.ac:201: installing './config.guess'
configure.ac:201: installing './config.sub'
configure.ac:14: installing './install-sh'
configure.ac:14: installing './missing'
Makefile.vex.am: installing './depcomp'
running: autoconf

 

configureコマンドを実行する。

$ ./configure --prefix=/where/you/want/it/installed --enable-only64bit
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... ./install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
(中略)
config.status: creating coregrind/link_tool_exe_darwin
config.status: creating coregrind/link_tool_exe_solaris
config.status: creating config.h
config.status: executing depfiles commands

         Maximum build arch: amd64
         Primary build arch: amd64
       Secondary build arch: 
                   Build OS: darwin
     Link Time Optimisation: no
       Primary build target: AMD64_DARWIN
     Secondary build target: 
           Platform variant: vanilla
      Primary -DVGPV string: -DVGPV_amd64_darwin_vanilla=1
         Default supp files: exp-sgcheck.supp xfree-3.supp xfree-4.supp darwin10-drd.supp darwin18.supp 

 

そしてmakeコマンドを実行したら終わり、のはずだが……エラーが出る。

$ make
echo "# This is a generated file, composed of the following suppression rules:" > default.supp
(中略)
/usr/bin/ar cru libvexmultiarch-amd64-darwin.a priv/libvexmultiarch_amd64_darwin_a-multiarch_main_main.o 
ranlib libvexmultiarch-amd64-darwin.a
Making all in coregrind
make[2]: *** No rule to make target `/usr/include/mach/mach_vm.defs', needed by `m_mach/mach_vmUser.c'.  Stop.
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

 

このエラーについてはStackOverflowの回答にも予想されているので、さらに指示に従って修正を加えていく。

まずはxcode-select --installを実行してxcode-selectをインストールする。

xcode-select --installをコマンドを実行すると次のようなダイアログが開く。

f:id:kidani_a:20190517023511p:plain

Xcode本体はインストールされているので、青の「インストール」ボタンをクリックすると、以下のように使用許諾契約のダイアログが表示される。

f:id:kidani_a:20190517023558p:plain

 

大人しく読んで「同意する」をクリックすると、インストールが開始される。

f:id:kidani_a:20190517023700p:plain

日頃の行いが悪いのか、ネットワークの調子が悪いのか、「残り9秒」->「残り10秒」->「残り11秒」と何故かカウントアップが始まってしまったが、数分待つと無事インストールが完了した。

f:id:kidani_a:20190517023725p:plain

 

xcode-selectのインストール完了後は、coregrind/Makefileファイルのam__append_19の箇所を以下のように修正する。

am__append_19 = \
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/mach_vm.defs \
        /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/task.defs \
        /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/thread_act.defs \
        /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/mach/vm_map.defs

 

ここでもう一度makeコマンドを実行するとvg_preloaded.c:136:19: error: expected ';' before 'const'というエラーが出るはずなのだが、以下のようなエラーが表示されてしまった。

$ make
./auxprogs/make_or_upd_vgversion_h .
/Applications/Xcode.app/Contents/Developer/usr/bin/make  all-recursive
Making all in include
(中略)
link_tool_exe_darwin: /usr/bin/ld -static -arch x86_64 -macosx_version_min 10.6 -o memcheck-amd64-darwin -u __start -e __start -image_base 0x158000000 -stack_addr 0x154000000 -stack_size 0x800000 memcheck_amd64_darwin-mc_leakcheck.o memcheck_amd64_darwin-mc_malloc_wrappers.o memcheck_amd64_darwin-mc_main.o memcheck_amd64_darwin-mc_main_asm.o memcheck_amd64_darwin-mc_translate.o memcheck_amd64_darwin-mc_machine.o memcheck_amd64_darwin-mc_errors.o ../coregrind/libcoregrind-amd64-darwin.a ../VEX/libvex-amd64-darwin.a
Undefined symbols for architecture x86_64:
  "_mach_msg_destroy", referenced from:
      __kernelrpc_mach_vm_allocate in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      __kernelrpc_mach_vm_deallocate in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      __kernelrpc_mach_vm_protect in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      _mach_vm_inherit in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      __kernelrpc_mach_vm_read in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      _mach_vm_read_list in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      _mach_vm_write in libcoregrind-amd64-darwin.a(libcoregrind_amd64_darwin_a-mach_vmUser.o)
      ...
ld: symbol(s) not found for architecture x86_64
make[3]: *** [memcheck-amd64-darwin] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

 

StackOverflowの回答欄をよく読むと、同じように「"_mach_msg_destroy"」関連のエラーメッセージが表示され、結局インストールできないという反応が寄せられている。

どうやら2019年5月現在では、macOS MojaveにValgrindを簡単にインストールする方法は無いようだ。

 

[symbol(s) not found]

ld: symbol(s) not found for architecture x86_64

それにしても、どこかで見覚えのあるエラーメッセージである。

 

以前、React Nativeアプリ開発の際に、Realmというデータベースを利用していたのだが、バージョンアップ時に何かを間違えたのか、起動しなくなってしまった。

kdnakt.hatenablog.com

kdnakt.hatenablog.com

 

このRealmのエラーについて困っているとTwitterに書いたところ、StackOverflowで聞いてみろとアドバイスを頂いたので質問をしてみたものの、未だに返答がない。

stackoverflow.com

 

前回のRealmの場合も今回のValgrindの場合も、C言語で実装されている部分で別のモジュールをインクルードしようとして失敗しているらしい、ということはエラーメッセージから何となく読み取ることができる。

 

何となく読み取ることはできるのだが、それをどう直せばいいのか、検討がつかない。見つからないと言われているシンボルでディレクトリ内を探してみても、それらしい内容のファイルが見当たらないのだ。きっと、バイナリで提供されているなどして、テキスト検索では検索できないようになっているのだろう、と推測している。

 

C言語については、去年軽くチュートリアルを触った程度でしかなく、初心者同然のレベルである。もう少し実戦経験を積んで、問題解決能力を身に付けていかねばと考えている(いつになることやら……)。

www.learn-c.org

 

[まとめ]

  • Rust By Exampleでは実コードを元にRustを学べる
  • Valgrindを使うとメモリリークなどを検出することができる
  • ただし、2019年5月時点のValgrind(3.15.0)はmacOS Mojave(バージョン 10.14.4)に対応していない
  • C言語関連(と思われる)エラーの対応は難しい