概要
Linux環境で正常に動いていたCMakeLists.txtを用いてiMacでターミナル経由でc++のプログラムをコンパイル・実行してAddressSanitizer(に内包されたLeakSanitizer)(https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer)
を用いてメモリリーク(newやmallocで確保したメモリの解放忘れなど)を検出しようとしたがされなかった。
丸1日以上かけて試行錯誤した結果、どうやらmac+clang8.0.0の環境下ではコンパイルオプションに-OgオプションがあるとAddressSanitizerが動かないようである事が分かった。
背景
xcodeでc++のプログラムを作成していた。xcodeに付属のclangのAddressSanitizerの機能(https://developer.apple.com/documentation/code_diagnostics/address_sanitizer/enabling_the_address_sanitizer)
でメモリリークを検知しようとしたところ、OSXのAddressSanitizerはメモリリークはデフォルトでは非対応で、自分で環境変数をASAN_OPTIONS=detect_leaks=1と設定する必要があるらしい。
(https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer)
ということで、xcodeのEdit Scheme > Run > Argumentsから環境変数ASAN_OPTIONSをdetect_leaks=1と設定した。が、実行してみるとメモリリークがあったことは教えてくれるものの、具体的な位置などは非対応、と言われてしまい出てこずデバッグにならなかった。どうやらxcodeに付属のclangではメモリリークは非対応のよう。
なのでメモリリークに対応したclangをインストールしてターミナル経由でプログラムをビルド・実行し、メモリリークを見つけることにした。
職場の先輩が、同じプログラムをLinuxでcmakeを用いてビルドするためのCMakeLists.txtを作成してくださったのでそれを利用することにした。
環境
iMac macOS Mojave バージョン10.14.4
やった事
clangのインストール・準備
以下のstack overflowの回答に従って、llvmのclangをダウンロード&設定。
(「echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> .zshrc
」やそれの読み込み部分に関してはインストール終了時にターミナルにこれらのコマンドを入力するように指示とコマンドが出るのでそれに従ってコマンドをコピペして実行したほうが間違いが無さそう。)
CMakeLists.txtでCMAKE_C_COMPILERとCMAKE_CXX_COMPILERに/usr/local/opt/llvm/bin/clangをセットしてやる。
https://stackoverflow.com/questions/53456304/mac-os-leaks-sanitizer
(which clangでclangの場所がxcode付属の物ではなくllvmの下のものになっていることも確認してやると尚良し?)環境変数ASAN_OIPTIONSの設定
export ASAN_OPTIONS=detect_leaks=1
を呼ぶ。
(又は~/.bash_profileにこれを書き込んで. ~/.bash_profileで読み込む)コンパイルオプション -fsanitize=addressをCMAKE_C_FLAGSとCMAKE_CXX_FLAGSに足してCMakeLists.txtのあるディレクトリに移動し、cmake .->make ->作成されたプロジェクトを実行
→これでメモリリークがある場合検出されるはず。…がされず。
コンパイルオプションに-Ogオプションがあるとメモリリークが検知されない!
検知されない原因はCMAKE_C_FLAGSとCMAKE_CXX_FLAGSに設定されていた-Ogオプションだったようで、これらを消したところちゃんと検出されるようになった。
Linux+gcc環境では-OgオプションがついていてもAddressSanitizerはちゃんと動くがmac+clangだと駄目なようだ。
-Ogオプションとは
最適化オプションの一つらしい。
(https://kaworu.jpn.org/cpp/g++_%E6%9C%80%E9%81%A9%E5%8C%96%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3#-Og)g++4.9の場合の-Ogオプションにより「有効になるオプション」に-fsanitizeに関する記述はないが、今回の環境のclang(clang 8.0.0)ではdisableにされちゃっている?
(https://kaworu.jpn.org/cpp/g%2B%2B_-Og%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E6%9C%80%E9%81%A9%E5%8C%96)
その他ハマった事
Cの標準ライブラリヘッダーを使用しようとしたところfatal error: 'stdlib.h' file not found #include <stdlib.h>などと出てコンパイルが通らない。
cmakeを用いず、ターミナルで直接
clang++ -g -std=gnu++11 -stdlib=libc++ -fsanitize=address main.cpp
としたところ、fatal error: 'stdlib.h' file not found #include <stdlib.h>などと出てコンパイルが通らなかった。
どうやらmacではデフォルトでは標準ヘッダーファイルがインストールされていないようで、
open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg
とコマンドを呼び、出てくるダイアログに従ってダウンロードしたら解決した。
(https://discourse.brew.sh/t/clang-can-no-longer-find-usr-include-header-files-fatal-error-stdlib-h-file-not-found/4523)