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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

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

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

文章目錄

  • 一、 簡(jiǎn)介
  • 二、AddressSanitizer 的使用
    • 使用方法
    • 1.使用添加編譯選項(xiàng)的方式使用ASan
    • 2.使用CMake添加編譯選項(xiàng)
  • 三、測(cè)試
      • 不添加Asan選項(xiàng),不會(huì)有任何輸出
      • 添加-fsanitize=address選項(xiàng):
      • 簡(jiǎn)單修改程序,釋放申請(qǐng)的內(nèi)存空間:
  • 四、不能在gdb、lldb等調(diào)試器運(yùn)行帶有AddressSanitizer的程序
  • 參考

一、 簡(jiǎn)介

所謂工欲善其事,必先利其器。在linux系統(tǒng)下進(jìn)行C++的開發(fā)時(shí),出現(xiàn)內(nèi)存訪問錯(cuò)誤是非常常見的事情,且大多數(shù)情況下gcc和gdb等編譯器和調(diào)試器都不會(huì)提示我們發(fā)生內(nèi)存錯(cuò)誤,通常會(huì)導(dǎo)致嚴(yán)重的后果且難以定位問題。

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

  • 對(duì)堆,棧和全局內(nèi)存的訪問越界(堆緩沖區(qū)溢出,棧緩沖區(qū)溢出,和全局緩沖區(qū)溢出)
  • UAP(Use-after-free,懸掛指針的解引用,或者說(shuō)野指針)
  • Use-after-return(無(wú)效的棧上內(nèi)存,運(yùn)行時(shí)標(biāo)記
  • ASAN_OPTIONS=detect_stack_use_after_return=1)
  • Use-After-Scope(作用域外訪問,clang 標(biāo)記 -fsanitize- address-use-after-scope )
  • 內(nèi)存的重復(fù)釋放
  • 初始化順序的 bug
  • 內(nèi)存泄漏

這個(gè)工具非???。通常情況下,內(nèi)存問題探測(cè)這類調(diào)試工具的引入,會(huì)導(dǎo)致原有應(yīng)用程序運(yùn)行性能的大幅下降,比如大名鼎鼎的 valgrind 據(jù)說(shuō)會(huì)導(dǎo)致應(yīng)用程序性能下降到正常情況的十幾分之一,但引入 AddressSanitizer 只會(huì)減慢運(yùn)行速度的一半。
使用 AddressSanitizer 可以在程序發(fā)生內(nèi)存問題的時(shí)候及時(shí)檢查出來(lái),精準(zhǔn)定位發(fā)生內(nèi)存問題的位置,大大提高我們debug的效率。


二、AddressSanitizer 的使用

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

使用方法

1.使用添加編譯選項(xiàng)的方式使用ASan

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

可選擇-O1或者更高的優(yōu)化級(jí)別編譯

2.使用CMake添加編譯選項(xiàng)

在CMakeLists文件中添加如下行

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

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

三、測(cè)試

以下程序是有兩個(gè)很明顯的內(nèi)存錯(cuò)誤:

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

不添加Asan選項(xiàng),不會(huì)有任何輸出

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$ 

編譯器的緘默不語(yǔ)是導(dǎo)致程序員痛苦整宿的元兇之一。

添加-fsanitize=address選項(xiàng):

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$ 

提示檢測(cè)到第五行出現(xiàn)內(nèi)存泄漏問題。原來(lái)是源程序new了一個(gè)對(duì)象,并沒有delete。

簡(jiǎn)單修改程序,釋放申請(qǐng)的內(nèi)存空間:

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

再次編譯運(yùn)行:

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行出現(xiàn)了heap-buffer-overflow。熟悉錯(cuò)誤信息的同學(xué)很快就能意識(shí)到,這是提示程序出現(xiàn)了越界訪問內(nèi)存的錯(cuò)誤。
通關(guān)這幾次測(cè)試,我們可以發(fā)現(xiàn),AddressSanitizer可以幫助我們快速定位編譯器檢測(cè)不出來(lái)的內(nèi)存問題,大大提高了我們debug的效率。

四、不能在gdb、lldb等調(diào)試器運(yùn)行帶有AddressSanitizer的程序

筆者就是為了記錄這個(gè)問題,特意包了這碗餃子。
當(dāng)嘗試使用gdb調(diào)試添加了AddressSanitizer編譯選項(xiàng)的程序時(shí),程序會(huì)拒絕執(zhí)行,提示:

==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)

根據(jù)網(wǎng)上找到的資料,LeakSanitizer在內(nèi)部使用ptrace,可能會(huì)掛起所有線程,以便它可以掃描泄漏而不會(huì)產(chǎn)生誤報(bào)。只有一個(gè)應(yīng)用程序可以使用ptrace,因此,如果您在gdb或strace下運(yùn)行應(yīng)用程序,則LeakSanitizer將無(wú)法通過ptrace進(jìn)行附加。

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

參考

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。