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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 长轮询的使用实现_长轮询和短轮询

    长轮询的使用实现_长轮询和短轮询轮询(Polling):是指不管服务器端有没有更新,客户端(通常是指浏览器)都定时的发送请求进行查询,轮询的结果可能是服务器端有新的更新过来,也可能什么也没有,只是返回个空的信息。不管结果如何,客户端处理完后到下一个定时时间点将继续下一轮的轮询。长轮询(LongPolling):长轮询的服务其客户端是不做轮询的,客户端在发起一次请求后立即挂起,一直到服务器端有更新的时候,服务器才会主动推送信息到…

    2025年6月17日
    1
  • pytest的使用_java中方法的调用

    pytest的使用_java中方法的调用Pytest执行用例规则Pytest在命令行中支持多种方式来运行和选择测试用例1.对某个目录下所有的用例pytest2.对模块中进行测试pytesttest_mod.py3.对文件夹进行

    2022年7月30日
    5
  • ARMv8 Linux内核异常处理过程分析「建议收藏」

    ARMv8 Linux内核异常处理过程分析

    2022年1月19日
    45
  • 动态页面和静态页面的区别

    动态页面和静态页面的区别静态页面 就是所有页面显示的内容都是写在 HTML 文件当的 如更改内容就是直接修改 HTML 文件 动态页面 就是内容不是写死在 HTML 文件当中的 页面的内容是通过像 asp php jsp cgi 格式文件 那样的编程语言输出 或编写访问数据库程序从数据库中和到的内容的 更改数据库就可以达到修改内容的目的 不用修改 HTML 文件 静态 动态的区分不是以页面有没有动画

    2025年6月6日
    3
  • java正则表达式匹配数字范围_在java中怎么利用正则表达式匹配数字

    java正则表达式匹配数字范围_在java中怎么利用正则表达式匹配数字在java中怎么利用正则表达式匹配数字发布时间:2020-12-0317:47:12来源:亿速云阅读:58作者:Leah在java中怎么利用正则表达式匹配数字?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。用于匹配的正则表达式为:([1-9]\d*\.?\d*)|(0\.\d*[1-9])([1-9]:匹配1~9的数字;\d…

    2022年6月21日
    33
  • python进阶(18)@wraps装饰器[通俗易懂]

    python进阶(18)@wraps装饰器[通俗易懂]前言我们都知道装饰器的作用是在不改变原有的代码基础上,添加新的功能,但是这样会有一个弊端,被装饰的函数某些属性会变改变,接下来我们来看下案例importtimedefrun_time(fu

    2022年8月7日
    3

发表回复

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

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