Address Sanitizer使用指南

Address Sanitizer使用指南提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档文章目录前言一 pandas 是什么 二 使用步骤 1 引入库 2 读入数据总结前言 AddressSanit 使用提示 以下是本篇文章正文内容 下面案例可供参考一 pandas 是什么 示例 pandas 是基于 NumPy 的一种工具 该工具是为了解决数据分析任务而创建的 二 使用步骤 1 引入库代码如下 示例 importnumpya


前言

使用C/C++编程,不可避免地会遭遇各种各样的内存异常。走查代码这种方式定位异常比较低效。在Linux平台下,Address Sanitizer是一个定位程序内存异常的高效分析工具。


一、Address Sanitizer简介

相比Valgrind,Address Sanitizer(ASan)要快很多,只会拖慢程序两倍左右。它包括一个编译器instrumentation模块和一个提供malloc()/free()替代项的运行时库。AddressSanitizer是gcc的一部分,本文采用gcc-7.5.0版本进行演示。

ASan可以检查如下几种内存异常:

  1. 内存错误操作:-fsanitize=address
  2. 多线程竞争:-fsanitize=thread
  3. 内存泄漏:-fsanitize=leak
  4. 未定义操作:-fsanitize=undefined(如:除0、空指针解引用、枚举值超范围、使用未初始化的变量值等)

二、使用步骤

1.安装gcc7.5.0

安装命令:

cd /opt tar -xvzf gcc-7.5.0.tar.gz -C /opt ln -sf /opt/gcc-7.5.0/bin/gcc /usr/bin/gcc-7.5.0 // 避免与系统自带gcc冲突,建立软连接 

2.编译程序

address.h:

#include <memory> #include <tr1/memory> #define MSG_LEN 128 class Cert { 
      public: Cert() { 
      printf("\nCert begin\n"); m_number = 0xFFFFFFFFFFFFFFFF; m_msg = new char[MSG_LEN+1]; memset(m_msg, 0, MSG_LEN + 1); printf("Cert end\n"); } ~Cert() { 
      printf("\n~Cert begin\n"); printf("~Cert end\n"); } public: unsigned long long m_number; char *m_msg; }; typedef std::tr1::shared_ptr<Cert> Cert_Ptr; 

address.cpp:

 /* 注意如下任意一种都不会生成内存检测报告: 1. 使用kill -9结束进程 2. 内存检测报告的文件路径无读写权限 */ #include <stdio.h> #include <string.h> #include <dlfcn.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <signal.h> #include <stdlib.h> #include "address.h" using namespace std; #ifdef Enable_AddressSanitizer static const char* __attribute__((unused)) ENABLE_AS = "Enable_AddressSanitizer"; void signal_handler(int signo); /* 结束进程: kill -s 3 PID */ void signal_handler(int signo) { 
      printf("%s", ENABLE_AS); if(SIGQUIT == signo) /* SIGQUIT: 3 */ { 
      exit(0); } } int output_stderr_to_file(char *logfilepath); int output_stderr_to_file(char *logfilepath) { 
      int result = -1; int logfd = open(logfilepath, O_CREAT|O_RDWR|O_APPEND); if(-1 != logfd) { 
      result = dup2(logfd, STDERR_FILENO); } return result; } #endif void test_func(); int main() { 
      #ifdef Enable_AddressSanitizer char szlogfilename[256] = { 
     0}; const char *pSanitizer = "Analyze_none"; #ifdef Analyze_address pSanitizer = "Analyze_address"; #endif #ifdef Analyze_thread pSanitizer = "Analyze_thread"; #endif #ifdef Analyze_leak pSanitizer = "Analyze_leak"; #endif #ifdef Analyze_undefined pSanitizer = "Analyze_undefined"; #endif char sztime[64] = { 
     0}; time_t tmNowT; time(&tmNowT); struct tm *tmNowS = localtime(&tmNowT); if(0 != tmNowS) { 
      sprintf(sztime, "%04d-%02d-%02d %02d_%02d_%02d", 1900+tmNowS->tm_year,1+tmNowS->tm_mon,tmNowS->tm_mday,tmNowS->tm_hour,tmNowS->tm_min,tmNowS->tm_sec); } else { 
      sprintf(sztime, "%04d-%02d-%02d %02d_%02d_%02d", 1900,1,1,0,0,0); } sprintf(szlogfilename, "./%s_%s.log", pSanitizer, sztime); output_stderr_to_file(szlogfilename); signal(SIGQUIT, signal_handler); #endif while(1) { 
      test_func(); sleep(1); } return 0; } void test_func() { 
      Cert* pCert = new Cert(); memcpy(pCert->m_msg, "2.0.1", MSG_LEN); char *p = new char[10*1024*1024]; } 

makefile

#gcc-4.9.4不支持选项 -fsanitize-recover=all,导致检查到内存错误时程序自动退出 CC= g++ ifeq ($(memcheck), address) CC= gcc-7.5.0 -fsanitize=address -fsanitize-recover=all -static-libasan -fno-omit-frame-pointer -DEnable_AddressSanitizer -DAnalyze_address else ifeq ($(memcheck), thread) CC= gcc-7.5.0 -fsanitize=thread -fsanitize-recover=all -shared -static-libtsan -fno-omit-frame-pointer -DEnable_AddressSanitizer -DAnalyze_thread else ifeq ($(memcheck), leak) CC= gcc-7.5.0 -fsanitize=leak -fsanitize-recover=all -static-liblsan -fno-omit-frame-pointer -DEnable_AddressSanitizer -DAnalyze_leak else ifeq ($(memcheck), undefined) CC= gcc-7.5.0 -fsanitize=undefined -fsanitize-recover=all -fno-omit-frame-pointer -DEnable_AddressSanitizer -DAnalyze_undefined endif #makefile 必须要有标签 all: ${ 
     CC} -g address.cpp -o address -I. -L. -lpthread -fPIC -lstdc++ 

编译脚本 build.sh

#!/bin/bash if [[ ${1} == memcheck=address ]]; then make $1 elif [[ ${1} == memcheck=thread ]]; then make $1 elif [[ ${1} == memcheck=leak ]]; then make $1 elif [[ ${1} == memcheck=undefined ]]; then make $1 else make fi 

编译脚本使用示例:

./build.sh memcheck=address #生成用于检测内存错误的应用程序 ./build.sh memcheck=thread #生成用于检测多线程竞争的应用程序 ./build.sh memcheck=leak #生成用于检测内存泄露的应用程序 ./build.sh memcheck=undefined #生成用于检测未定义操作的应用程序 

3.设置运行环境

上述步骤为编译环境操作,如下是 运行环境的设置。需要设置gcc7.5.0的路径信息:导入gcc7.5.0自带的lib64路径

#若设置用户的环境变量,需执行source命令 export LD_LIBRARY_PATH=/opt/gcc-7.5.0/lib64:$LD_LIBRARY_PATH #告诉address检测到异常不退出进程 export ASAN_OPTIONS=halt_on_error=0 

4.运行程序

# 注:运行环境要有gcc-7.5.0:拷贝gcc-7.5.0.tar 解压至opt目录 ./address 

5.分析内存检测报告

# 运行一段时间后,kill掉进程,程序会自动生成内存检测报告 kill -3 `pidof address` 

内存检测报告:

[root@localhost test_AddressSanitizer]# cat yangyulong_Analyze_address_2021-08-10\ 17_31_42.log ================================================================= ==29819==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000005105c6 at pc 0x00000045b832 bp 0x7ffdf0 sp 0x7ffda0 READ of size 128 at 0x0000005105c6 thread T0 #0 0x45b831 in __interceptor_memcpy ../../.././libsanitizer/asan/asan_interceptors.cc:456 #1 0x4fa7f9 in test_func() /home/debug/test_AddressSanitizer/address.cpp:90 #2 0x4fa788 in main /home/debug/test_AddressSanitizer/address.cpp:80 #3 0x7f5f846a8b34 in __libc_start_main (/lib64/libc.so.6+0x21b34) #4 0x405dcb (/home/debug/test_AddressSanitizer/address+0x405dcb) 0x0000005105c6 is located 0 bytes to the right of global variable '*.LC9' defined in 'address.cpp' (0x5105c0) of size 6 '*.LC9' is ascii string '2.0.1' SUMMARY: AddressSanitizer: global-buffer-overflow ../../.././libsanitizer/asan/asan_interceptors.cc:456 in __interceptor_memcpy Shadow bytes around the buggy address: 0x00008009a060: 01 f9 f9 f9 f9 f9 f9 f9 01 f9 f9 f9 f9 f9 f9 f9 0x00008009a070: 00 04 f9 f9 f9 f9 f9 f9 00 01 f9 f9 f9 f9 f9 f9 0x00008009a080: 00 00 00 f9 f9 f9 f9 f9 03 f9 f9 f9 f9 f9 f9 f9 0x00008009a090: 00 00 00 00 00 00 00 00 00 05 f9 f9 f9 f9 f9 f9 0x00008009a0a0: 00 00 f9 f9 f9 f9 f9 f9 00 00 00 06 f9 f9 f9 f9 =>0x00008009a0b0: 00 00 07 f9 f9 f9 f9 f9[06]f9 f9 f9 f9 f9 f9 f9 0x00008009a0c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x00008009a0d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x00008009a0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x00008009a0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x00008009a100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ================================================================= ==29819==ERROR: LeakSanitizer: detected memory leaks Direct leak of  byte(s) in 7 object(s) allocated from: #0 0x4c0610 in operator new[](unsigned long) ../../.././libsanitizer/asan/asan_new_delete.cc:82 #1 0x4fa803 in test_func() /home/debug/test_AddressSanitizer/address.cpp:92 #2 0x4fa788 in main /home/debug/test_AddressSanitizer/address.cpp:80 #3 0x7f5f846a8b34 in __libc_start_main (/lib64/libc.so.6+0x21b34) Direct leak of 96 byte(s) in 6 object(s) allocated from: #0 0x4c0470 in operator new(unsigned long) ../../.././libsanitizer/asan/asan_new_delete.cc:80 #1 0x4fa7a9 in test_func() /home/debug/test_AddressSanitizer/address.cpp:89 #2 0x4fa788 in main /home/debug/test_AddressSanitizer/address.cpp:80 #3 0x7f5f846a8b34 in __libc_start_main (/lib64/libc.so.6+0x21b34) Indirect leak of 774 byte(s) in 6 object(s) allocated from: #0 0x4c0610 in operator new[](unsigned long) ../../.././libsanitizer/asan/asan_new_delete.cc:82 #1 0x4fa8ba in Cert::Cert() /home/debug/test_AddressSanitizer/address.h:13 #2 0x4fa7b4 in test_func() /home/debug/test_AddressSanitizer/address.cpp:89 #3 0x4fa788 in main /home/debug/test_AddressSanitizer/address.cpp:80 #4 0x7f5f846a8b34 in __libc_start_main (/lib64/libc.so.6+0x21b34) SUMMARY: AddressSanitizer:  byte(s) leaked in 19 allocation(s). 

检测报告各部分介绍:

  1. ERROR:指出错误类型是global-buffer-overflow
  2. READ:指出线程名thread T0,操作为READ,发生的位置是address.cpp:90
  3. SUMMARY:前面输出的概要说明

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233256.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 接口-DAO模式代码阅读及应用

    接口-DAO模式代码阅读及应用

    2021年10月6日
    51
  • windows查看tomcat版本信息

    windows查看tomcat版本信息tomcat提供了查看版本信息的bat工具,

    2025年5月30日
    0
  • Pytorch 转置卷积

    Pytorch 转置卷积环境使用Kaggle里免费建立的Notebook教程使用李沐老师的动手学深度学习网站和视频讲解小技巧:当遇到函数看不懂的时候可以按查看函数详解。卷积不会增大输入的高和宽,通常要么不变,要么减半。而转置卷积则可以用来增大输入高宽。假设忽略通道,步幅为1且填充为0。输入张量形状为nh×nwn_h\timesn_wnh​×nw​,卷积核形状为kh×kwk_h\timesk_wkh​×kw​。共产生nhnwn_hn_wnh​nw​个中间结果。每个中间结果都是一个(nh+k

    2022年6月21日
    24
  • MYSQL中TINYINT的取值范围

    原文地址:https://blog.csdn.net/lysygyy/article/details/5983433在MySQL的数据类型中,Tinyint的取值范围是:带符号的范围是-128到127。无符号的范围是0到255(见官方《MySQL5.1参考手册》http://dev.mysql.com/doc/refman/5.1/zh/column-types.html#numeri…

    2022年4月5日
    49
  • pycharm远程部署_远程连接服务器失败

    pycharm远程部署_远程连接服务器失败在这之前你要确保服务器上已经创建好虚拟环境你本地已经安装好pycharm1创建本地文件远程服务器上已经有一个文件了。现在你在本地创建一个同名文件。服务器上的虚拟环境为DrQA,所以我在本地新建一个DrQA空文件夹。2用pycharm打开空项目3配置服务器的解释器左上角File→Setting→projectxxx→pythoninterpreter点右上角的小齿轮,然后点add选择SSHInterpreter,然后在上边填上服务器的地址、usernam

    2022年8月25日
    4
  • Date与Quartz的cron之间的相互转换「建议收藏」

    Date与Quartz的cron之间的相互转换「建议收藏」实现Date与Quartz的cron之间的相互转换.

    2022年6月17日
    30

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号