私のライブラリdoctestは、travis CI - x86/x64 Debug/Release linux/osx 上の 200 以上のビルドと、gcc 4.4 から 6 および clang 3.4 から 3.8 までの幅広いコンパイラでテストされています。
すべてのテストは、valgrind とアドレス サニタイザー (UB サニタイザー) を介して実行されます。
私は最近、ASAN のすべての機能がデフォルトでオンになっているわけではないことを発見しました。たとえば、次のとおりです。
check_initialization_order=true
detect_stack_use_after_return=true
strict_init_order=true
そのため、それらを有効にすると、以下の例のようなコードでエラーが発生し始めました。
int& getStatic() {
static int data;
return data;
}
int reg() { return getStatic() = 0; }
static int dummy = reg();
int main() { return getStatic(); }
でコンパイルg++ (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010
:
g++ -fsanitize=address -g -fno-omit-frame-pointer -O2 a.cpp
そして次のように走りました:
ASAN_OPTIONS=verbosity=0:strict_string_checks=true:detect_odr_violation=2:check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true ./a.out
次のエラーが発生します。
==23425==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_globals.cc:255 "((dynamic_init_globals)) != (0)" (0x0, 0x0)
#0 0x7f699bd699c1 (/usr/lib/x86_64-linux-gnu/libasan.so.2+0xa09c1)
#1 0x7f699bd6e973 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0xa5973)
#2 0x7f699bcf2f5c in __asan_before_dynamic_init (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x29f5c)
#3 0x40075d in __static_initialization_and_destruction_0 /home/onqtam/a.cpp:10
#4 0x40075d in _GLOBAL__sub_I__Z9getStaticv /home/onqtam/a.cpp:10
#5 0x40090c in __libc_csu_init (/home/onqtam/a.out+0x40090c)
#6 0x7f699b91fa4e in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x20a4e)
#7 0x4007b8 in _start (/home/onqtam/a.out+0x4007b8)
同じですg++-6 (Ubuntu 6.1.1-3ubuntu11~12.04.1) 6.1.1 20160511
次の 3 つのいずれかを実行すると、エラーは消えます。
- g++ の代わりに clang++ (任意のバージョン) を使用する
- を取り外して
-O2
使用-O0
static
の前を削除します。dummy
なぜこうなった?バグの場合 - 報告されていますか? それを避ける方法は?
編集:
@vadikrobot は、これでも次のように述べてstatic int data = 0; static int dummy = data; int main() { }
います。問題が発生します。
編集:
@eadの答えは正しいですが、静的ダミーの削除を回避する方法を見つけたので、asanはもうアサートしません:
int& getStatic() {
static int data = 0;
return data;
}
int __attribute__((noinline)) reg(int* dummy_ptr) { *dummy_ptr = 5; return getStatic() = 0; }
static int __attribute__((unused)) dummy = reg(&dummy);
int main(int argc, char** argv) { return getStatic(); }