内存分析工具的使用——AddressSanitizer

一、c/c++中的内存问题

memory corruption,内存崩溃或者说内存损坏。在c/c++程序中,有相当一部分的Bug是由内存引起的,也就是刚刚提到的内存崩溃。说得再通俗一些,往往和内存的非法访问有关。内存问题,轻则导致程序失能,中则导致程序崩溃,重则引起系统瘫痪。
因此,在c/c++编程的过程中,对内存的管理要求非常严格。但灵活多变的指针往往又让很多开发者无法安全的进行内存的处理,即使在新的C++标准中使用了智能指针或者说自行进行了RAII的封装,仍然有可能造成指针引起的内存错误。当然,并不是说c/c++中指针是内存问题的万恶之源,其它情况如数组越界访问等均可以出现类似的问题。
基于上面的内存的问题,很多针对内存进行控制的相关工具也有很多。其中,有静态内存检查工具(Cppcheck等)和动态内存检查工具(valgrind等)。本文介绍一个动态内在检查工具,GAS。

二、GAS

GAS,google address sanitizer,也称为ASan,它是google公司开发的一个快速的内在检测工具。相比于Valgrind对程序的影响,ASan的速度那相当快了。要想监测内存,最好的办法是什么?当然是替换掉编译器的相关内存管理接口了。ASan就提供了一个插桩模块(编译器检测模块LLVM pass)和一个提供malloc等函数替代接口的运行时库。
ASan早期就与LLVM(3.1)进行了结合,将其插桩模块整合到了Clang项目中。后来在Gcc4.8中,也整合了GAS的相关模块,但其配合不太完善,所以推荐使用Gcc4.9以上版本。ASan还有一个专门提供给内核使用的版本KASAN,有兴趣可以搞一下。

三、基本原理

ASan使用的内存检测机制是使用影子内存(shadow memory)来记录当前内存是否可以安全访问的方式。其通过影子内存与常规内存(normal memory)进行映射以期安全的管理内存。通过代码插桩来检查程序运行时影子内存的状态。
当编译器运行时,其通过替代的分配内存管理接口,在内存分配和回收后的区域进行“投毒”(poisoned),形成所谓的有毒区域(如果有visual studio系列的反汇编的经验会很容易理解这段话,其实就是对内存进行二次标记管理并设置相关的安全管理区域),这个其它的动态内存管理如数组安全检测的机理基本类似。关于影子内存映射的机理和相关细节,请查阅谷歌相关论文,此处不再赘述。

四、ASan支持的内存检查

ASan对常见的内存问题都进行了支持,主要包括下面几点:
1、Use after free
这个比较好理解,它主要是指堆(Heap)内存在释放后又被重新使用。这是一种非常常见的内存问题,类似于下面的代码:

A *a = new A();
delete a;
a->pid = 0;

2、Heap buffer overflow
这也是一种比较常见的内存错误,即堆内存溢出,也就是越界:

char * p = new char[10];
p[11] = 2;

3、Stack buffer overflow
说过了堆溢出怎么能不提栈溢出呢,这个就不举例子了,太简单多见了。
4、Global buffer overflow
全局缓冲区溢出,这都和堆溢出类似。
5、Use after return
返回值使用无效内存,典型的就是返回一个临时变量的指针或引用,看下面的代码:

int * getData(){
  int tmp[10];
  return tmp;
}
int * d = getData();

6、Use after scope
使用作用域外的内存空间,和上面的有些类似。看下面的代码:

for(int i = 0;i< 10;i++){}
int p = i;

7、Initialization order bugs
初始化顺序不同引用的问题,这个比较符合C++的特性。这个在前面的分析过好多次,最典型的就是库中的全局变量与调用者之间调用之间的顺序问题,静态变量也有这种可能的现象。
8、Memory leaks
内存泄露,这可是写c/c++程序员的“亲亲”。不管多么高深的开发者,几乎都会遇到这个问题。但有一句话需要说明:内存泄露不可怕,可怕是内存泄露的累积。

五、应用

在基本了解了ASan后,下面举一个例子来进行实践一把。使用ASan的主要步骤分为:

1、编写测试程序

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int heapOver() {
  char *pBuf = (char *)malloc(10 * sizeof(char));
  memcpy(pBuf + 10, "abcd1234", 8);
  free(pBuf);

  return 0;
}
int *getData() {
  int *arr = new int[10];
  delete arr;
  return arr;
}
int main() {
  heapOver();
  int arr[10] = {0};
  int d = arr[11];

  int *p = getData();
  delete p;

  return 0;
}

2、在编译时增加相关参数
gcc中增加-fsanitize=address选项;如果想获得较好性能,建议增加-O1或更高编译优化选项;增加fno-omit-frame-pointer选项可以提供更友好的堆栈回溯信息

3、编译并运行:

#编译:注意如果不加-g选项,则无法准确的显示出问题的源码位置,可自行测试一下不带-g
~/project/ASanTest$ g++  -fsanitize=address -fno-omit-frame-pointer -g -o asanTest main.cpp
#运行
~/project/ASanTest$ ./asanTest 
=================================================================
==94673==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001a at pc 0x7f6acbe3a2c3 bp 0x7ffde51ff060 sp 0x7ffde51fe808
WRITE of size 8 at 0x60200000001a thread T0
    #0 0x7f6acbe3a2c2 in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
    #1 0x55b7993f9381 in heapOver() /home/qt65_project/ASanTest/main.cpp:8
    #2 0x55b7993f9477 in main /home/fqt65_project/ASanTest/main.cpp:19
    #3 0x7f6acb629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #4 0x7f6acb629e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #5 0x55b7993f9284 in _start (/home//qt65_project/ASanTest/asanTest+0x1284)

0x60200000001a is located 0 bytes to the right of 10-byte region [0x602000000010,0x60200000001a)
allocated by thread T0 here:
    #0 0x7f6acbeb4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x55b7993f935e in heapOver() /home/qt65_project/ASanTest/main.cpp:7
    #2 0x55b7993f9477 in main /home/fqt65_project/ASanTest/main.cpp:19
    #3 0x7f6acb629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
Shadow bytes around the buggy address:
  0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00[02]fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: 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:           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
  Shadow gap:              cc
==94673==ABORTING

大家可以依次的进行测试,就会将三种类型的问题,都在运行时暴露出来。分别报得错误是“堆溢出、栈溢出和分配释放不匹配”。而且描述的非常详细和准确,大家可以自己动手实践一把。

六、总结

工欲善其事,必先利其器。不是常说,某某是编程界的瑞士军刀么。其实,只要是刀,用好了都会起到事半功倍的效果。要想写出好的代码,除了有思想上的指导,在实践中熟练的应用各种开发工具也是必不可少的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/889635.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何快速给word文件加拼音?请跟着步骤完成吧

如何快速给word文件加拼音&#xff1f;在日常工作中&#xff0c;我们时常会遇到需要为Word文件中的文字添加拼音的情况&#xff0c;这尤其在教育、出版或国际交流等领域显得尤为重要。为文字配上拼音&#xff0c;不仅能帮助学习者准确发音&#xff0c;还能提升文档的可读性和普…

【JavaEE初阶】深入理解不同锁的意义,synchronized的加锁过程理解以及CAS的原子性实现(面试经典题);

前言 &#x1f31f;&#x1f31f;本期讲解关于锁的相关知识了解&#xff0c;这里涉及到高频面试题哦~~~ &#x1f308;上期博客在这里&#xff1a;【JavaEE初阶】深入理解线程池的概念以及Java标准库提供的方法参数分析-CSDN博客 &#x1f308;感兴趣的小伙伴看一看小编主页&am…

【STM32单片机_(HAL库)】4-2-1【定时器TIM】定时器输出PWM实现呼吸灯实验

1.硬件 STM32单片机最小系统LED灯模块 2.软件 pwm驱动文件添加定时器HAL驱动层文件添加GPIO常用函数定时器输出PWM配置步骤main.c程序 #include "sys.h" #include "delay.h" #include "led.h" #include "pwm.h"int main(void) {HA…

【瑞萨RA8D1 CPK开发板】串口的使用和STDOUT输出重定向

串口 本次串口的使用关于时钟导致串口的波特率不对&#xff0c;坑了我很久的时间 使能时钟 串口发现一个问题就是&#xff0c;只能使用下边的时钟配置&#xff0c;修改时钟源和分频系数都会导致串口波特率不正常&#xff0c;这种问题出现在mdkrasc的使用场景之下&#xff1b…

adaptor lora基础

https://www.zhihu.com/question/508658141/answer/3340979311 adaptor和PEFT的区别&#xff1a;前者在模型子层后加一个小型的dense&#xff1b;后者直接稀疏化模型本身&#xff1b; Loading Pre-Trained Adapters — AdapterHub documentation CVPR 2024 | SD-DiT&#xff…

Python | Leetcode Python题解之第468题验证IP地址

题目&#xff1a; 题解&#xff1a; class Solution:def validIPAddress(self, queryIP: str) -> str:if queryIP.find(".") ! -1:# IPv4last -1for i in range(4):cur (len(queryIP) if i 3 else queryIP.find(".", last 1))if cur -1:return &q…

每日OJ题_牛客_小乐乐改数字_模拟_C++_Java

目录 牛客_小乐乐改数字_模拟 题目解析 C代码 Java代码 牛客_小乐乐改数字_模拟 小乐乐改数字_牛客题霸_牛客网 (nowcoder.com) 描述&#xff1a; 小乐乐喜欢数字&#xff0c;尤其喜欢0和1。他现在得到了一个数&#xff0c;想把每位的数变成0或1。如果某一位是奇数&#…

【网络安全】CVE-2024-46990: Directus环回IP过滤器绕过实现SSRF

未经许可,不得转载。 文章目录 背景漏洞详情受影响版本解决方案背景 Directus 是一款开源 CMS,提供强大的内容管理 API,使开发人员能够轻松创建自定义应用程序,凭借其灵活的数据模型和用户友好的界面备受欢迎。然而,Directus 存在一个漏洞,允许攻击者绕过默认的环回 IP …

大数据之——VWare、Ubuntu、CentOs、Hadoop安装配置

前言&#xff1a;这里很抱歉前几期考研专题以及PyTorch这些内容都没有更新&#xff0c;并不是没有在学了&#xff0c;而是事太鸡儿多了&#xff0c;前不久刚刚打完华为开发者比赛&#xff0c;然后有紧接着高数比赛、考研复习&#xff0c;因此这些后续文章都在草稿状态中&#x…

Allegro在PCB上开槽的三种方法操作指导

Allegro如何在PCB上开槽的三种方法操作指导 当PCB有特殊设计要求的时候&#xff0c;需要在PCB上开槽&#xff0c;Allegro支持在PCB上开槽操作&#xff0c;具体操作如下 以下图为例&#xff0c;需要在这个板框中间开槽 开方形槽 选择shape add rect命令 画在Board Geometry-o…

【技术详解】SpringMVC框架全面解析:从入门到精通(SpringMVC)

文章目录 【技术详解】SpringMVC框架全面解析&#xff1a;从入门到精通(SpringMVC)SpringMVC概述1. 三层架构与MVC架构区别1.1 三层架构1.2 MVC架构1.3前后端分离开发模式 2. SpringMVC环境搭建2.1 注解启动方式2.2 xml启动方式2.3 SpringMVC PostMan工具使用 3. SpringMVC 请求…

MySQL 实验1:Windows 环境下 MySQL5.5 安装与配置

MySQL 实验1&#xff1a;Windows 环境下 MySQL5.5 安装与配置 目录 MySQL 实验1&#xff1a;Windows 环境下 MySQL5.5 安装与配置一、MySQL 软件的下载二、安装 MySQL三、配置 MySQL1、配置环境变量2、安装并启动 MySQL 服务3、设置 MySQL 字符集4、为 root 用户设置登录密码 一…

【华为欧拉】国产OpenEuler服务器系统安装以及图形界面

openEuler下载 | openEuler ISO镜像 | openEuler社区官网 下载安装iso 本次选择4G的社区版本 安装&#xff0c;复制到光盘&#xff0c;光盘引导安装。虚拟机安装&#xff0c;准备好iso文件引用&#xff0c;指定好安装源&#xff0c;安装界面和centOS基本一样。选择最小安装就…

代码随想录算法训练营第三十天|491. 非递减子序列,46. 全排列,47. 全排列 II,332. 重新安排行程,51. N 皇后,37. 解数独

491. 非递减子序列&#xff0c;46. 全排列&#xff0c;47. 全排列 II&#xff0c;332. 重新安排行程&#xff0c;51. N 皇后&#xff0c;37. 解数独 491. 非递减子序列46. 全排列47. 全排列 II332. 重新安排行程51. N 皇后37. 解数独 491. 非递减子序列 给你一个整数数组 nums…

友思特方案 | FantoVision边缘计算:嵌入式视觉系统如何实现“更快 更高 更强”?

导读 便于集成的嵌入式视觉系统一直以来面临着带宽、内存、算力三个方面的挑战。友思特 FantoVision 边缘计算设备拥有更快的处理速度和更高的带宽选择&#xff0c;其开放式架构有效突破了上述三重阻碍。 嵌入式视觉 嵌入式视觉是传统机器视觉衍生出来的子集&#xff0c;嵌入…

k8s 中存储之 PV 持久卷 与 PVC 持久卷申请

目录 1 PV 与 PVC 介绍 1.1 PersistentVolume&#xff08;持久卷&#xff0c;简称PV&#xff09; 1.2 PersistentVolumeClaim&#xff08;持久卷声明&#xff0c;简称PVC&#xff09; 1.3 使用了PV和PVC之后&#xff0c;工作可以得到进一步的细分&#xff1a; 2 持久卷实验配置…

UE5运行时动态加载场景角色动画任意搭配-相机及运镜(二)

通过《MMD模型及动作一键完美导入UE5》系列文章,我们可以把外部场景、角色、动画资产导入UE5,接下来我们将实现运行时动态加载这些资产,并任意组合搭配。 1、运行时播放相机动画 1、创建1个BlueprintActor,通过这个蓝图动态创建1个LevelSequence,并Play 2、将这个Bluep…

Verdin AM62使用CODESYS

By Toradex 胡珊逢 简介 CODESYS 是基于 IEC 61131-3 的 PLC 开发工具&#xff0c;在工业控制、交通等领域中有着广泛的应用。文章将介绍如何在 Toradex 采用 TI AM62 SoC 的 Arm 计算机模块 Verdin AM62 使用评估版本的 CODESYS。 硬件介绍 Verdin AM62使用 TI AM623/AM625…

打卡第四天 P1081 [NOIP2012 提高组] 开车旅行

今天是我打卡第四天&#xff0c;做个省选/NOI−题吧(#^.^#) 原题链接&#xff1a;[NOIP2012 提高组] 开车旅行 - 洛谷 题目描述 输入格式 输出格式 输入输出样例 输入 #1 4 2 3 1 4 3 4 1 3 2 3 3 3 4 3 输出 #1 1 1 1 2 0 0 0 0 0 输入 #2 10 4 5 6 1 …

✨机器学习笔记(七)—— 交叉验证、偏差和方差、学习曲线、数据增强、迁移学习、精确率和召回率

机器学习笔记&#xff08;七&#xff09; 1️⃣评估模型&#x1f397;️使用测试集评估模型&#x1f397;️交叉验证集&#xff08;cross validation&#xff09; 2️⃣偏差和方差&#xff08;Bias / Variance&#xff09;3️⃣学习曲线&#xff08;Learning curves&#xff09…