Memory sanitizer
-
Upload
mitsunari-shigeo -
Category
Technology
-
view
462 -
download
0
Transcript of Memory sanitizer
![Page 1: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/1.jpg)
MemorySanitizer:
fast detector of uninitialized memory use in C++
2015/7/8
光成滋生
![Page 2: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/2.jpg)
C/C++の未初期化メモリ実行時チェックツール
http://research.google.com/pubs/pub43308.html の紹介
動作速度のコストは2.5x, メモリ使用量は2x程度
Clangに組み込まれていて-fsanitize=memoryで利用可能
未初期化メモリ(UUM : Use of Uninitialized Memory)の
トラッキングも可能
実際にGoogleのたくさんの開発で利用されている
2/11
MemorySanitizer(以下MSan)
![Page 3: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/3.jpg)
valgrind(Memcheck)
UUM、ヒープオーバーフロー、free後の利用の検出
1byteに2bitの情報
addressable+init, not addr, addr+uninit, addr+partially init
false positiveが0に近い
20x遅い(マルチスレッドでもっと遅い)
Dr. Memory
Memcheckの2xほど
マルチスレッドでちょっとfalse positive
Intel Inspector XE
遅い
3/11
Related work
![Page 4: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/4.jpg)
各1bitに1bit割り当てる(0:init/defined, 1:not)
Shadow = App & (~0x4000|032)
Originはトラッキングのときに使う
どちらもMAP_NORESERVEをつける(Swap対象としない)
4/11
Shadow memory
Application
Origin
Shadow
Protected 0x0000|032
0x2000|032
0x4000|032
0x6000|032
0x7fff|132
![Page 5: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/5.jpg)
UM(未初期化メモリ)は伝達する
C++11では未初期化objectのlvalueからrvalueへの変換は未定義だった
C++14でindeterminate valueに緩和される
struct A { char x; int y; };を8byteのmemcpyに最適化されてもエラーを出さないように
UMにしたがって条件分岐、システムコールの呼び出し、ポインタdereferenceしたときにエラーを出力
5/11
Shadow propagation
![Page 6: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/6.jpg)
false positiveを出さない方針
その条件の元でできるだけfalse negativeを減らす
記号 : A = B op C(オリジナル), A', B', C':shadow
6/11
Shadow propagation rule
命令 ルール
A = load P check P', load (P & shadowMask)
*P = A check P', *(P & shadowMask) = A'
A = const A' = 0
A = undef A' = 0xff
A = B & C A' = (B'&C')|(B&C')|(B'&C)
A = B | C A' = (B'&C')|(~B&C')|(B'&~C)
A = B ^ C A' = B' | C'
A = B << C A' = (sign extend(C'!=0))|(B'<<C)
![Page 7: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/7.jpg)
A = B * (C * (1 << D))
A' = B' << Dで代用(一般はA' = B'| C')
bitwiseにやってるとfalse positiveになる例
clangはこれを *(unsigned char*)s > 7と最適化する
X : unsigned, X':対応するshadowのとき
Xのとり得る範囲は[VMin(X, X'), VMax(X, X')]
VMin(X, X') = X & (~X')
VMax(X, X') = X | X'
正確だがベンチマークで50%の速度低下
7/11
複雑なパターン(1/2)
struct S { int a:3; int b:5; }; bool f(S* s) { return s->b; }
![Page 8: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/8.jpg)
等号比較
A = B == Cを
D = B ^ C, A = D == 0に変換
D' = B'|C', A'=(!(D & ~D')) && (D' != 0)
条件演算子
A = B ? C : D
BがundefでもCとDが同じでdefならAはdefになる
A' = B' ? ((C ^ D) | C' | D') : (B ? C' : D')
8/11
複雑なパターン(2/2)
![Page 9: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/9.jpg)
vector instruction
同じ数だけ並べる
thread safety
global lockは遅いので別のやりかたで
CAS, RMWは以前の値は全てinitializedと仮定
function calls
va_listの扱いが大変
run-time library
300ほどの関数をintercept
9/11
その他
![Page 10: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/10.jpg)
valgrindの10倍ぐらい速い
10/11
performance
![Page 11: Memory sanitizer](https://reader036.fdocument.pub/reader036/viewer/2022081807/55c73f6dbb61eb4e6e8b46e8/html5/thumbnails/11.jpg)
未初期化参照が分かってもそれがどこにあったか分からないと辛い
源流を保持する
11/11
origin tracking
#include <stdio.h> int arr[2]; void shift() { arr[1] = arr[0]; } void push(int *p) { shift(); arr[0] = *p; } int pop() { int x = arr[1]; shift(); return x; } void func1() { int local_var; push(&local_var); } int main() { func1(); shift(); return pop(); }
clang-3.5 -fsanitize-memory-track-origins=2 -g -fsanitize=memory t.c && ./a.out ==22068== WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x7f87ee79de13 (/home/shigeo/a.out+0x8ee13) #1 0x7f87ed600ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4) #2 0x7f87ee79d7bc (/home/shigeo/a.out+0x8e7bc) ... Uninitialized value was created by an allocation of 'local_var' in the stack frame of function 'func1' #0 0x7f87ee79dce0 (/home/shigeo/a.out+0x8ece0) SUMMARY: MemorySanitizer: use-of-uninitialized-value ??:0 ?? ちなみにgcc t.c -Wall –Wextraでは警告は何もでない。 % valgrind --track-origins=yes ./a.out ==22149== Syscall param exit_group(status) contains uninitialised byte(s) ==22149== at 0x4EF8309: _Exit (_exit.c:32) ==22149== by 0x4E7321A: __run_exit_handlers (exit.c:97) ==22149== by 0x4E732A4: exit (exit.c:104) ==22149== by 0x4E58ECB: (below main) (libc-start.c:321) ==22149== Uninitialised value was created by a stack allocation ==22149== at 0x400560: func1 (t.c:13)