日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

LINUX 下使用Address Sanitizer ,以及不能运行的问题

發布時間:2023/12/3 综合教程 33 生活家
生活随笔 收集整理的這篇文章主要介紹了 LINUX 下使用Address Sanitizer ,以及不能运行的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 一、 簡介
  • 二、AddressSanitizer 的使用
    • 使用方法
    • 1.使用添加編譯選項的方式使用ASan
    • 2.使用CMake添加編譯選項
  • 三、測試
      • 不添加Asan選項,不會有任何輸出
      • 添加-fsanitize=address選項:
      • 簡單修改程序,釋放申請的內存空間:
  • 四、不能在gdb、lldb等調試器運行帶有AddressSanitizer的程序
  • 參考

一、 簡介

所謂工欲善其事,必先利其器。在linux系統下進行C++的開發時,出現內存訪問錯誤是非常常見的事情,且大多數情況下gcc和gdb等編譯器和調試器都不會提示我們發生內存錯誤,通常會導致嚴重的后果且難以定位問題。

AddressSanitizer (ASan)是一個性能非常好的 C/C++ 內存錯誤探測工具。它由編譯器的插樁模塊(目前,LLVM 通過)和替換了 malloc 函數的運行時庫組成。這個工具可以探測如下這些類型的錯誤:

  • 對堆,棧和全局內存的訪問越界(堆緩沖區溢出,棧緩沖區溢出,和全局緩沖區溢出)
  • UAP(Use-after-free,懸掛指針的解引用,或者說野指針)
  • Use-after-return(無效的棧上內存,運行時標記
  • ASAN_OPTIONS=detect_stack_use_after_return=1)
  • Use-After-Scope(作用域外訪問,clang 標記 -fsanitize- address-use-after-scope )
  • 內存的重復釋放
  • 初始化順序的 bug
  • 內存泄漏

這個工具非常快。通常情況下,內存問題探測這類調試工具的引入,會導致原有應用程序運行性能的大幅下降,比如大名鼎鼎的 valgrind 據說會導致應用程序性能下降到正常情況的十幾分之一,但引入 AddressSanitizer 只會減慢運行速度的一半。
使用 AddressSanitizer 可以在程序發生內存問題的時候及時檢查出來,精準定位發生內存問題的位置,大大提高我們debug的效率。


二、AddressSanitizer 的使用

自 LLVM 的版本 3.1 和 GCC 的版本 4.8 開始,AddressSanitizer 就是它們的一部分。因此只要版本正確,無需額外鏈接庫或者編譯源碼,只需編譯的時候加上選項即可使用。

使用方法

1.使用添加編譯選項的方式使用ASan

  • 使用-fsanitize=address選項編譯和鏈接你的程序。
    例如:
gcc -fsanitize=address -O1 -g -o  main main.cpp 
  • 如果有其他需要,加上-fno-omit-frame-pointer等其他編譯選項
gcc -fsanitize=address -fno-omit-frame-pointer -O1 -g -o main main.cpp

可選擇-O1或者更高的優化級別編譯

2.使用CMake添加編譯選項

在CMakeLists文件中添加如下行

set(CMAKE_CXX_FLAGS_DEBUG  "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address")

對于AddressSanitizer還有很多編譯選項,這里不一一列舉,若有需要自行去官方文檔查詢。

三、測試

以下程序是有兩個很明顯的內存錯誤:

#include <iostream>
using namespace std;int main() {char *c = new char(10);c[1] = 'a';return 0;
}

不添加Asan選項,不會有任何輸出

ubuntu@VM-24-14-ubuntu:~/CppTest$ g++ -O1 -g -o test test.cpp 
ubuntu@VM-24-14-ubuntu:~/CppTest$ ./test
ubuntu@VM-24-14-ubuntu:~/CppTest$ 

編譯器的緘默不語是導致程序員痛苦整宿的元兇之一。

添加-fsanitize=address選項:

ubuntu@VM-24-14-ubuntu:~/CppTest$ g++ -fsanitize=address -O1 -g -o test test.cpp 
ubuntu@VM-24-14-ubuntu:~/CppTest$ ./test 
==175312==AddressSanitizer: libc interceptors initialized
|| `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
|| `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
|| `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap  ||
|| `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
|| `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
MemToShadow(shadow): 0x00008fff7000 0x000091ff6dff 0x004091ff6e00 0x02008fff6fff
redzone=16
max_redzone=2048
quarantine_size_mb=256M
thread_local_quarantine_size_kb=1024K
malloc_context_size=30
SHADOW_SCALE: 3
SHADOW_GRANULARITY: 8
SHADOW_OFFSET: 0x7fff8000
==175312==Installed the sigaction for signal 11
==175312==Installed the sigaction for signal 7
==175312==Installed the sigaction for signal 8
==175312==T0: stack [0x7ffc3e50a000,0x7ffc3ed0a000) size 0x800000; local=0x7ffc3ed08294
==175312==AddressSanitizer Init done
==175313==Processing thread 175312.
==175313==Stack at 0x7ffc3e50a000-0x7ffc3ed0a000 (SP = 0x7ffc3ed07e88).
==175313==TLS at 0x7fba89ae14c0-0x7fba89ae2580.=================================================================
==175312==ERROR: LeakSanitizer: detected memory leaksDirect leak of 1 byte(s) in 1 object(s) allocated from:#0 0x7fba8a165587 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:104#1 0x55840905425a in main /home/ubuntu/CppTest/test.cpp:5SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).
ubuntu@VM-24-14-ubuntu:~/CppTest$ 

提示檢測到第五行出現內存泄漏問題。原來是源程序new了一個對象,并沒有delete。

簡單修改程序,釋放申請的內存空間:

#include <iostream>
using namespace std;int main() {char *c = new char(10);c[1] = 'a';delete c;return 0;
}

再次編譯運行:

ubuntu@VM-24-14-ubuntu:~/CppTest$ g++ -fsanitize=address -O1 -g -o test test.cpp 
ubuntu@VM-24-14-ubuntu:~/CppTest$ ./test 
==175937==AddressSanitizer: libc interceptors initialized
|| `[0x10007fff8000, 0x7fffffffffff]` || HighMem    ||
|| `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
|| `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap  ||
|| `[0x00007fff8000, 0x00008fff6fff]` || LowShadow  ||
|| `[0x000000000000, 0x00007fff7fff]` || LowMem     ||
MemToShadow(shadow): 0x00008fff7000 0x000091ff6dff 0x004091ff6e00 0x02008fff6fff
redzone=16
max_redzone=2048
quarantine_size_mb=256M
thread_local_quarantine_size_kb=1024K
malloc_context_size=30
SHADOW_SCALE: 3
SHADOW_GRANULARITY: 8
SHADOW_OFFSET: 0x7fff8000
==175937==Installed the sigaction for signal 11
==175937==Installed the sigaction for signal 7
==175937==Installed the sigaction for signal 8
==175937==T0: stack [0x7ffc9bbc7000,0x7ffc9c3c7000) size 0x800000; local=0x7ffc9c3c5014
==175937==AddressSanitizer Init done
=================================================================
==175937==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000011 at pc 0x55ebd66cc2de bp 0x7ffc9c3c4ff0 sp 0x7ffc9c3c4fe0
WRITE of size 1 at 0x602000000011 thread T0#0 0x55ebd66cc2dd in main /home/ubuntu/CppTest/test.cpp:6#1 0x7fa58b097082 in __libc_start_main ../csu/libc-start.c:308#2 0x55ebd66cc1cd in _start (/home/ubuntu/CppTest/test+0x11cd)0x602000000011 is located 0 bytes to the right of 1-byte region [0x602000000010,0x602000000011)
allocated by thread T0 here:#0 0x7fa58b6c0587 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:104#1 0x55ebd66cc29a in main /home/ubuntu/CppTest/test.cpp:5SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/CppTest/test.cpp:6 in main
Shadow bytes around the buggy address:0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):Addressable:           00Partially addressable: 01 02 03 04 05 06 07 Heap left redzone:       faFreed heap region:       fdStack left redzone:      f1Stack mid redzone:       f2Stack right redzone:     f3Stack after return:      f5Stack use after scope:   f8Global redzone:          f9Global init order:       f6Poisoned by user:        f7Container overflow:      fcArray cookie:            acIntra object redzone:    bbASan internal:           feLeft alloca redzone:     caRight alloca redzone:    cbShadow gap:              cc
==175937==ABORTING
ubuntu@VM-24-14-ubuntu:~/CppTest$ 

這次提示又不一樣了,提示第6行出現了heap-buffer-overflow。熟悉錯誤信息的同學很快就能意識到,這是提示程序出現了越界訪問內存的錯誤。
通關這幾次測試,我們可以發現,AddressSanitizer可以幫助我們快速定位編譯器檢測不出來的內存問題,大大提高了我們debug的效率。

四、不能在gdb、lldb等調試器運行帶有AddressSanitizer的程序

筆者就是為了記錄這個問題,特意包了這碗餃子。
當嘗試使用gdb調試添加了AddressSanitizer編譯選項的程序時,程序會拒絕執行,提示:

==163135==LeakSanitizer has encountered a fatal error.
==163135==HINT: For debugging, try setting environment variable LSAN_OPTIONS=verbosity=1:log_threads=1
==163135==HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)

根據網上找到的資料,LeakSanitizer在內部使用ptrace,可能會掛起所有線程,以便它可以掃描泄漏而不會產生誤報。只有一個應用程序可以使用ptrace,因此,如果您在gdb或strace下運行應用程序,則LeakSanitizer將無法通過ptrace進行附加。

說人話就是,LINUX系統下只同時允許一個進程使用ptrace()這個系統調用,而ptrace是用于進程跟蹤的,它提供了父進程可以觀察和控制其子進程執行的能力,并允許父進程檢查和替換子進程的內核鏡像(包括寄存器)的值。
gdb等調試器也會使用ptrace,因此與LeakSanitizer相沖突,不允許執行進程。

參考

Address Sanitizer 用法
Linux 下的 AddressSanitizer
c++ Asan(address-sanitize)的配置和使用
Ptrace 詳解

總結

以上是生活随笔為你收集整理的LINUX 下使用Address Sanitizer ,以及不能运行的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。