一篇知晓-内存竟被”无意“破坏,真相究竟如何?

news2025/1/15 13:10:28

内存是C/C++程序员的好帮手,我们通常说C/C++程序性能更高其原因之一就在于可以自己来管理内存,然而计算机科学中没有任何一项技术可以包治百病,内存问题也给C/C++程序员带来无尽的烦恼。

野指针、数组越界、错误的内存分配或者释放、多线程读写导致内存被破坏等等,这些都会导致某段内存中的数据被”无意“的破坏掉,这类bug通常很难定位,因为当程序开始表现异常时通常已经距离真正出问题的地方很远了,常用的程序调试方法往往很难排查此类问题。

既然这类问题通常是由于内存的读写造成,那么如果要是某一段内存被修改或者读取时我们能观察到此事件就好了,幸运的是这类技术已经实现了。

一段示例

在GDB中你可以通过添加watchpoint来观察一段内存,这段内存被修改时程序将会停止,此时我们就能知道到底是哪行代码对该内存进行了修改,这功能是不是很强大。

接下来我们用示例来讲解一下,有这样一段代码:

#include <iostream>
#include <thread>
using namespace std;

// 线程修改变量值
void memory_write(int* value) {
  *value = 1;
}

int main()
{
    int a = 10;
    // 获取局部变量a的地址
    int* c = &a;

    for (int i = 0; i < 100; i++) {
      a += i;
    }

    cout << a << endl;

    // 将变量a的地址传递到线程
    thread t(memory_write, c);
    t.join();

    return 0;
}

这段代码非常简单,创建局部变量a,然后获取变量a的地址并赋值给指针c,此后对变量a进行累加和,然后输出a的值,此时a的值为4960。

假设此后你发现变量a的值竟然变为了1,然而由于代码非常复杂你并不知道到底是哪段代码对变量a进行修改,在上述代码中我们利用线程a来模拟这个场景,线程获取变量a的地址后对其进行了修改,将其变为了1,接下来我们利用调试工具gdb来定位到底是谁修改了变量a。

   资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

开始捕捉“肇事者”

对上述代码进行编译,接下来利用gdb进行调试,假设源文件的名称是a.cc,编译后的可执行程序名字为a:

$ gdb a.out
(gdb) b a.cc:20
Breakpoint 1 at 0x400f23: file a.cc, line 20.
(gdb) r
Starting program: /bin/a
Breakpoint 1, main () at a.cc:20
20          cout << a << endl;

上述调试命令(b a.cc:20)表示我们在代码的第20行加断点,当程序运行到这里后暂停,调试命令r表示开始运行程序,可以看到运行到第20行后暂停,此时我们查看一下变量a的地址:

(gdb) p &a
$1 = (int *) 0x7fffffffe508

可以看到,变量a位于内存地址0x7fffffffe508,接下来重点来了,我们该怎样告诉gdb让它帮我们时刻监测0x7fffffffe508这个内存地址中的值有没有被修改呢?很简单:

(gdb) watch *(int*)0x7fffffffe508
Hardware watchpoint 2: *(int*)0x7fffffffe508

我们利用watch命令,让gdb帮我们时刻监测一段从0x7fffffffe508开始大小为4字节的内存区域(假设int占据4字节),这就是watch *(int*)0x7fffffffe508这行指令的含义:

除此之外上面gdb的输出中还有一段值得注意:

Hardware watchpoint 2: *(int*)0x7fffffffe508

注意看,什么是Hardware watchpoint呢?先卖个关子,我们稍后聊,接下来我们运行gdb中的c命令,意思是continue,让程序继续运行:

(gdb) c
Continuing.
4960

此时第20行执行完毕并打印出了变量a的值4960,我们接着往下看:

[New Thread 0x7ffff6f5c700 (LWP 531823)]
[Switching to Thread 0x7ffff6f5c700 (LWP 531823)]
Hardware watchpoint 2: *(int*)0x7fffffffe508

Old value = 4960
New value = 1
memory_write (value=0x7fffffffe508) at a.cc:8
8       }
(gdb)

哈哈,gdb成功的捕捉到了是哪一行代码修改了0x7fffffffe508这块内存,而且详细的告诉我们所有信息,可以看到gdb打印出了这块内存之前保存的数据是数字4960,修改后的值为1,并且是在a.cc:8这里被修改的,而这里正是我们创建的线程对变量a进行修改的地方,gdb成功的捕捉到了”肇事者“,原来是这个线程”无意“修改了变量a的值。

是不是很神奇,那么这一切都是怎样实现的呢?

watchpoint是怎样实现的?

原来这一切都是CPU的功劳。

现代处理器中具有特殊的debug寄存器,x86处理器中是DR0到DR7寄存器,利用这些寄存器硬件可以持续检测处理器发出的用于读写内存的地址,更强大的是,不但硬件watchpoint可以检查内存地址,而且还是可以监测到底是在读内存还是在写内存。

利用gdb中的rwatch命令你可以来监测是否有代码读取了某段内存;利用gdb中的awatch命令你可以来检查是否有代码修改了某段内存;利用gdb中的watch命令你可以检查对某段内存是否有读或者写这两种情况。

一旦硬件监测到相应事件,就会暂停程序的运行并把控制权交给debugger,也就是这里的gdb,此时我们就可以对程序的状态进行详细的查看了,这种硬件本身支持的调试能力就是刚才提到的Hardware watchpoint

有hardware watchpoint就会有software watchpoint,当硬件不支持hardware watchpoint时gdb会自动切换到software watchpoint,此时你的程序每被执行一条机器指令gdb就会查看相应的事件是否发生,因此software watchpoint要远比hardware watchpoint慢,你可以利用gdb中的”set can-use-hw-watchpoints“命令来控制gdb该使用哪类watchpoint。

值得注意的是,在多线程程序中software watchpoint作用有限,因为如果被检测的一段内存被其它线程修改(就像本文中的示例)那么gdb可能捕捉不到该事件。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kotlin之hello world

如果你想一个人写全栈的话&#xff0c;Kotlin Multiplatform &#xff08;以下简称MPP&#xff09;是目前这个星球上最好的选择&#xff0c;没有之一。 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言&#xff0c;被称之为 Android 世界的Swift&#xff0c;由 JetBrain…

CTFSHOW web入门 java反序列化篇(更新中)

在做这部分题前&#xff0c;推荐大家先去学习下java反序列化&#xff0c;尤其是CC链 可以看下两个系列视频&#xff0c;收获颇多 https://space.bilibili.com/2142877265/channel/collectiondetail?sid29805&ctype0 https://www.bilibili.com/video/BV16h411z7o9/?spm_i…

手写Spring2(实现 Bean 的定义、注册、获取)

文章目录前言本章目标一、实现1、项目结构2、BeanFactory-bean工厂3、BeanDefinition -bean定义4、单例注册接口定义和实现-SingletonBeanRegistry 、DefaultSingletonBeanRegistry5、AbstractBeanFactory-抽象bean工厂类(定义模板方法)6、AbstractAutowireCapableBeanFactory-…

python配置环境问题记录------2022/12/07

python配置问题记录1、版本匹配的问题2、指令安装相关依赖包3、pycharm指定解释器4、运行网络模块5、总结1、版本匹配的问题 到官网下载合适的版本&#xff08;注意位数&#xff0c;我这里选的是64位&#xff09;&#xff0c;pycharm选的是21年版本的&#xff0c;太新的话会有…

【C++】异常exception

目录 一.C语言错误处理方式 1.assert(断言) 2.返回/设置错误码 二.C异常的概念与使用 1.异常的概念 2.异常的使用 三.自定义异常体系MyException 四.异常的重新抛出 五.异常安全问题 六.异常规范 七.异常的优缺点对比 一.C语言错误处理方式 一个C语言程序, 在运行期…

回归分析与相关分析的区别和联系

在本节中&#xff0c;我们将首先讨论相关性分析&#xff0c;它用于量化两个连续变量之间的关联&#xff08;例如&#xff0c;独立变量与因变量之间或两个独立变量之间&#xff09;。 最近我们被客户要求撰写关于回归分析与相关分析的研究报告&#xff0c;包括一些图形和统计输…

软件测试经验与教训

下面精选出10条&#xff0c;和大家分享。 01 测试人员是项目的前灯 一个项目就像是一次陆上旅行。有些项目很简单、很平常&#xff0c;就像是大白天开车去商店买东西。但是大多数值得开发的项目更像是夜间在山里开越野卡车&#xff0c;这些项目需要前灯&#xff0c;而测试员要照…

直播带货行业如何入局?先了解一下直播商城源码吧

直播行业的爆火已经持续了多个年头&#xff0c;直到今天&#xff0c;在人们的生活中依然有着举足轻重的地位&#xff0c;它通过多元化的方案为许多行业带来了新的思路&#xff0c;特别是与传统商业所结合的“直播电商”、“直播商城”的卖货新形式&#xff0c;让多方因此而受益…

数理化解题研究杂志社数理化解题研究编辑部2022年第30期目录

教学改革探索 信息技术下中职数学“翻转课堂”教学创新策略研究 李宇仙; 2-4《数理化解题研究》投稿&#xff1a;cn7kantougao163.com 基于高中数学核心素养的错题讲评课之探索与实践 施浩妹; 17-20 高中数学“问题导学”模式的实践研究 吴金桥; 21-23 立于神而…

【测试沉思录】21. 如何用 JMeter 编写性能测试脚本?

作者&#xff1a;宋赟 编辑&#xff1a;毕小烦 Apache JMeter 应该是应用最广泛的性能测试工具。怎么用 JMeter 编写性能测试脚本&#xff1f; 1. 编写 HTTP 性能测试脚本 STEP 1. 添加 HTTP 请求 STEP 2. 了解配置信息 HTTP 请求各项信息说明&#xff08;以 JMeter 5.1 为例…

【强化学习论文合集】十.2018智能体和多智能体系统国际联合会议论文(AAMAS2018)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

十四、SpringBoot-自动装配原理

十四、SpringBoot-自动装配原理 SpringBoot与Spring比较起来&#xff0c;优化的点主要有&#xff1a; 自动配置&#xff1a;是一个运行时&#xff08;应用程序启动时&#xff09;的过程&#xff0c;考虑了众多因素&#xff0c;才决定Spring配置应该用哪个&#xff0c;不该用哪…

软件测试基础丨测试工程师之间要善于发现闪光点——测试理念篇

测试理念有多种&#xff0c;有一些理念&#xff0c;深藏于我的心中&#xff0c; 而这些理念&#xff0c;您或许偶尔想到&#xff0c;却没有说出&#xff0c;或许您感受到了&#xff0c;却因为工作生活的忙碌&#xff0c;没有将其背后的含义想具体&#xff0c; 在此我非常愿意和…

零基础小白hadoop分布式集群环境搭建(超详细)

搭建集群所需要安装包 虚拟机、ubuntu镜像文件、jdk安装包、hadoop安装包 百度云盘地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ejVamlrlyoWtJRo1QQqlsA提取码&#xff1a;fcqm 本文的环境是两台windows笔记本&#xff0c;在每台笔记本上安装一个虚拟机&…

超详细的水果FL Studio21最新版更新全功能详细介绍!80项更新与改进!

万众期待的 FL Studio 21 版本将于正式发布上线&#xff0c;目前在紧锣密鼓的安排上线中&#xff0c;届时所有购买正版 FL Studio 的用户&#xff0c;都可以免费升级到21版&#xff01;按照惯例&#xff0c;本次新版也会增加全新插件&#xff0c;来帮助大家更好地创作。今天先给…

SMART原则介绍

一、SMART原则简介 什么是SMART原则? SMART原则(S=Specific、M=Measurable、A=Attainable、R=Relevant、T=Time-bound)是为了利于员工更加明确高效地工作,更是为了管理者将来对员工实施绩效考核提供了考核目标和考核标准,使考核更加科学化、规范化,更能保证考核的公正、…

五万字详解“GoF”的23种设计模式

大家好&#xff0c;我是栗筝i&#xff0c;近期我总结梳理了 “GoF”的 23 种设计模式&#xff0c;并使用 Java 对每种设计模式都进行了伪代码与 Demo 实现&#xff0c;并总结了每种设计模式的应用场景&#xff0c;优缺点&#xff0c;UML图等相关内容&#xff0c;字/词数达到了5…

Java中的String

/*** 关于java.lang.String类* 1、String表示字符串类型&#xff0c;属于引用数据类型&#xff0c;不属于基本数据类型* 2、在java中用双引号括起来的都是String对象* 3、java中规定&#xff0c;字符串是不可变的* 4、字符串存储在方法区的字符串常量池当中*/ …

单例模式(python)

一、模式定义 1. 单例模式(Singleton Pattern)&#xff1a;确保某一个类只有一个实例&#xff0c;而且自行实例化并向整个系统提供这个实例&#xff0c;这个类称为单例类&#xff0c;它提供全局访问的方法。 2. 单例模式的要点有三个&#xff1a; 某个类只能有一个实例 必须自…

[激光原理与应用-41]:《光电检测技术-8》- 白光干涉仪

目录 第1章 白光干涉仪概述 第2章 常见干涉仪 2.1 激光量块干涉仪 2.2 白光干涉测量表面形貌的系统 第1章 白光干涉仪概述 用于光在两个不同表面反射后形成的干涉条纹进行分析的设备。 干涉仪是一种对光在两个不同表面反射后形成的干涉条纹进行分析的仪器。 其基本原理就…