首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

AddressSanitizer (ASan) 完全指南:原理、編譯與 Android 實戰

     編輯:關於C語言

什麼是 AddressSanitizer?

AddressSanitizer(簡稱 ASan)是 Google 開發的高效記憶體錯誤檢測工具,類似 Valgrind 但採用編譯期插桩技術。它能檢測:

  • 緩衝區溢出(堆/棧/全局)
  • Use-after-free / Use-after-return
  • 雙重釋放、野指針解引用
  • 記憶體洩漏(配合 LSAN)

核心原理:編譯期插桩 + 影子記憶體

編譯時加入 -fsanitize=address,編譯器會:

  1. 將 malloc、free、memcpy 等替換為 ASan 版本
  2. 在每次記憶體存取前插入檢查代碼
  3. 維護一個「影子記憶體」映射,每 8 位元組應用記憶體對應 1 位元組影子值,標記地址是否可訪問

這使檢測開銷極低(典型 2x 慢down、記憶體 2-3x),遠優於 Valgrind 的 20-50x。

主流編譯器支援

  • LLVM/Clang ≥ 3.1
  • GCC ≥ 4.8
  • MSVC ≥ 19.0 (VS2019 16.9+ 完整支援)

啟用只需添加編譯/鏈接旗標 -fsanitize=address,優化等級建議 -O1 或更高(-O0 會漏報部分錯誤)。

Android 平台深度整合

Android 4.2+ 內建 ASan(源碼在 external/compiler-rt/lib/asan)。僅 eng 版預設編譯。使用步驟:

  1. 在 Android.mk 添加 LOCAL_ADDRESS_SANITIZER := true
  2. 修復頭文件包含衝突(ASan 會修改系統頭文件行為)
  3. 編譯產出 libasan_preload.so 和 asanwrapper

兩種運行模式

模式一:asanwrapper 啟動

asanwrapper /system/bin/xxx --options

模式二:LD_PRELOAD 注入(通用)

分析 asanwrapper.cc 可見其本質:設置環境變量 LD_PRELOAD=/system/lib/libasan_preload.so 並 execv 目標程式。因此對於 APK,只需在 app_process 的 Android.mk 開啟 ASan,再用 asan_device_setup.sh 配置設備即可。

實戰避坑指南

  • 符號化堆棧:配合 llvm-symbolizer 或 addr2line 將報錯地址轉為源碼行號
  • 抑制誤報:使用 __attribute__((no_sanitize_address)) 標註誤報函數,或編寫 .sanitizer_ignore 文件
  • 組合使用:-fsanitize=address,undefined 同時開啟 UBSan(未定義行為檢測)
  • 生產環境:ASan 不適合發布版,但可用於 CI/CD 流水線的壓力測試階段

總結

ASan 以「編譯期插桩 + 影子記憶體」實現了極致的性能/檢測力平衡,已成為 C/C++ 專案 CI 流水線的標配。Android 開發者更應善用其系統級整合,徹底消滅記憶體類 Crash。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved