9 Aralık 2019 Pazartesi

gcc -fsanitize Seçeneği

Giriş
C++ uygulamalarında hataları bulmak için bazı notlarım şöyle. -fsanitize seçeneği
address - memory leak içindir. Asan kütüphanesi kullanılır
thread -  thread hataları içindir
undefined - tanımsız davranışlar içindir. Ubscan kütüphanesi kullanılır
parametreleri ile çağrılabilir. Tüm sanitizer seçenekleri kodun miktarını artırdığı için bazı optimizasyonlar devre dışı kalabilir. Açıklaması şöyle
Sanitizers add necessary instrumentation to detect violations at run-time. That instrumentation may prevent the function from being computed at compile-time as an optimization by introducing some opaque calls/side-effects that wouldn't be present there otherwise.
-fsanitize=address seçeneği
libasan (AddressSanitizer) ile linkler. Bu kütüphane memory leak bulmaya yardımcı olur. Açıklaması şöyle.
Previously, the most commonly used memory error detect tool was Valgrind, but the biggest problem with Valgrind is that it will greatly reduce program speed, by 10 times by estimate.

The good news is that the Google-developed memory error detect tool, AddressSanitizer (aka ASan), has greatly improved the program slowdown to two times only on average, which is very fast.
AddressSanitizer Nedir?
Açıklaması şöyle
AddressSanitizer is a compiler-based testing tool that detects various memory errors in C/C++ code at runtime.

Strictly speaking, AddressSanitizer is a compiler plug-in. It consists of two modules:

- A compiler instrumentation module.
- A run-time library that replaces malloc/free.

The instrumentation module mainly deals with memory operations, such as store and load at the compiler level.

The dynamic library mainly provides some complex functions at runtime, such as poison/unpoison shadow memory and a hooks system calling functions, such as malloc/free.
AddressSanitizer Ne Tür Hataları Yakalar?
Açıklaması şöyle
According to the official Wiki, AddressSanitizer finds:

Use after free (dangling pointer dereference)
Heap buffer overflow
Stack buffer overflow
Global buffer overflow
Use after return
Use after scope
Initialization order bugs
Memory leaks
Force the program to crash upon errors.
Normalde AddressSanitizer hataları raporlar Eğer ilk hata uygulama crash etsion istersek çalıştığımız kabukta şöyle bir ortam değişkeni tanımlarız.
export ASAN_OPTIONS='abort_on_error=1'/
Örnek - Use After Free
AddressSanitierz şu kodu yakalar
int main(int argc, char **argv) {
  int *array = new int[100];
  delete [] array;
  std::cout << array[0] << std::endl;
  return 1;
}
Örnek - Memory Leak
AddressSanitierz şu kodu yakalar
void *p;
int main() {
  p = malloc(7);
  p = 0; // The memory is leaked here.
  return 0;
}
Örnek - Memory Leak Çıktısı
Şöyle yaparız.
g++ -g -fsanitize=address myprogram.cpp -o myprogram
Çıktı olarak şunu alırız.
There are 2 leaks ...
Cls is leaked
Cls is leaked

=================================================================
==71254==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1 byte(s) in 1 object(s) allocated from:
    #0 0x7fe67c2c69d7 in operator new(unsigned long) (/lib64/libasan.so.5+0x10f9d7)
    #1 0x4057a6 in main /home/edward/test/memleak/src/main.cpp:97
    #2 0x7fe67bcbb1a2 in __libc_start_main (/lib64/libc.so.6+0x271a2)

Direct leak of 1 byte(s) in 1 object(s) allocated from:
    #0 0x7fe67c2c69d7 in operator new(unsigned long) (/lib64/libasan.so.5+0x10f9d7)
    #1 0x405774 in main /home/edward/test/memleak/src/main.cpp:95
    #2 0x7fe67bcbb1a2 in __libc_start_main (/lib64/libc.so.6+0x271a2)

SUMMARY: AddressSanitizer: 2 byte(s) leaked in 2 allocation(s).

-fsanitize=thread seçeneği
Örnek
Çıktı şöyle olabilir.
WARNING: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread)
Örnek
Şöyle yaparız.
g++ -std=c++11 -O0 -g -fsanitize=thread issue49.cpp -o issue49 -pthread
Çıktı olarak şuna benzer bir şey alırız.
==================
WARNING: ThreadSanitizer: data race (pid=17220)
  Read of size 4 at 0x0000006051c0 by thread T1:
    #0 FakeQueue::try_dequeue(int&) issue49.cpp:26 (issue49+0x000000402bcd)
    ...

  Previous write of size 4 at 0x0000006051c0 by main thread:
    #0 FakeQueue::enqueue(int) issue49.cpp:16 (issue49+0x000000402a90)
    ...

  Location is global 'q' of size 4008 at 0x0000006051c0 (issue49+0x0000006051c0)

  Thread T1 (tid=17222, running) created by main thread at:
    #0 pthread_create <null> (libtsan.so.0+0x000000027a67)
    ...

SUMMARY: ThreadSanitizer: data race issue49.cpp:26 FakeQueue::try_dequeue(int&)
==================
ThreadSanitizer: reported 1 warnings
-fsanitize=undefined seçeneği
Açıklaması şöyle.
In order to check your program with ubsan, compile and link the program with -fsanitize=undefined option. Such instrumented binaries have to be executed; if ubsan detects any problem, it outputs a “runtime error:” message, and in most cases continues executing the program. There is a possibility of making these diagnostic messages abort — just use the option -fno-sanitize-recover.
Örnek
Elimizde şöyle bir kod olsun.
int main() {
    int i = 23;
    i <<= 32; 
}
Bu kodu çalıştırınca şu çıktıyı alırız.
runtime error: shift exponent 32 is too large for 32-bit type 'int'
Bir başka kullanım şekli ve açıklaması şöyle. Bu özellik GCC 6 optimizer ile geliyor.
Value range propagation now assumes that the this pointer of C++ member functions is non-null. This eliminates common null pointer checks but also breaks some non-conforming code-bases (such as Qt-5, Chromium, KDevelop). As a temporary work-around -fno-delete-null-pointer-checks can be used. Wrong code can be identified by using -fsanitize=undefined.
Tüm problem C tarzı kodlamanın C++ diline uygulanmasından kaynaklanıyor.

Hiç yorum yok:

Yorum Gönder