多线程内存问题分析之mprotect方法【转】
转自:https://blog.csdn.net/agwtpcbox/article/details/53230664
http://www.yebangyu.org/blog/2016/02/01/detectmemoryghostinmultithread/
多线程中的内存问题,一直被认为是噩梦般的存在,几乎只有高手、大仙才能解决。除了大量的打log、gdb调试、code review以及依靠多年的经验和直觉之外,有没有一些分析的手段和工具呢?答案是肯定的。本文首先介绍其中的一种:mprotect大法。通过mprotect,保护特定的感兴趣的内存,当有线程改写该区域时,会产生一个中断,我们在中断处理函数中把调用栈等信息打印出来。这是大概的思路,不过其中的问题很多,我们慢慢道来。
原理
mprotect函数
mprotect函数的原型如下:
int mprotect(const void *addr, size_t len, int prot);
其中addr是待保护的内存首地址,必须按页对齐;len是待保护内存的大小,必须是页的整数倍,prot代表模式,可能的取值有PROT_READ(表示可读)、PROT_WRITE(可写)等。
不同体系结构和操作系统,一页的大小不尽相同。如何获得页大小呢?通过PAGE_SIZE宏或者getpagesize()系统调用即可。
定制中断处理函数
当线程试图对我们已保护(成只读)的内存进行篡改时,默认情况下程序会收到SIGSEGV错误而退出。能不能不退出并且把相应的调用栈打印出来分析?当然可以。通过如下代码注册你定制的中断处理函数即可:
- struct sigaction act;
 - act.sa_sigaction = your_handler;
 - sigemptyset(&act.sa_mask);
 - act.sa_flags = SA_SIGINFO;
 - if(sigaction(SIGSEGV, &act, NULL) == -1) {
 - perror("Register hanlder failed");
 - exit(EXIT_FAILURE);
 - }
 
这样,控制流就会到达你编写的your_handler函数上。而your_handler的函数原型是:
void your_handler(int sig, siginfo_t *si, void *unused);
编写your_handler函数即可?是的,不过这里面有两个注意事项:
1,中断处理函数里不应该调用内存分配函数,否则可能会引起double fault。因此,不适合调用backtrace_symbols(内部会动态分配内存),而是通过backtrace_symbols_fd直接将调用栈信息直接刷到文件中。
2,中断处理函数中应该恢复被保护内存为可写,否则会引起死循环。(再次中断并进入咱们编写的函数)
封装
为了方便使用,我封装了一个类,供参考:
1  | 
  | 
这个封装还存在一些问题,比如缺少错误处理,待保护内存必须在一页内等。读者诸君可以根据需要自行完善。
实战
来个例子,实战一下吧
1  | 
  | 
用如下方式编译链接以上程序:
g++ -g -rdynamic -std=c++11 -pthread  test.cpp -o test
程序运行结束后,打开result.tmp文件,看到如下内容:
- ./test(_ZN14MemoryDetector12my_backtraceEv+0x26)[0x405ce8]
 - ./test(_ZN14MemoryDetector7handlerEiP7siginfoPv+0x60)[0x405cc0]
 - /lib64/libpthread.so.0[0x339a80f500]
 - ./test(_Z1gv+0x25)[0x405909]
 - ./test(_ZNSt6thread5_ImplIPFvvEE6_M_runEv+0x16)[0x406e2c]
 - /usr/lib64/libstdc++.so.6[0x3a6f6b6490]
 - /lib64/libpthread.so.0[0x339a807851]
 - /lib64/libc.so.6(clone+0x6d)[0x339a4e767d]
 
注意其中的第四行:./test(_Z1gv+0x25)[0x405909]。使用addr2line命令:
addr2line -e test 0x405909
获得非法篡改的代码位置:
/home/yebangyu/test.cpp:13
真相大白了。
多线程内存问题分析之mprotect方法【转】的更多相关文章
- Android 内存泄漏分析与解决方法
		
在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...
 - MFC多线程内存泄漏问题&解决方法
		
在用visual studio进行界面编程时(如MFC),前台UI我们能够通过MFC的消息循环机制实现.而对于后台的数据处理.我们可能会用到多线程来处理. 那么对于大多数人(尤其是我这样的菜鸟),一个 ...
 - Android handler 内存泄露分析及解决方法
		
1. 什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引 ...
 - Java内存溢出分析方法(Eclipse Memory Analyzer 使用简单入门)
		
转载至:http://outofmemory.cn/java/jvm/OutOfMemoryError-analysis 工具 安装Memory Analyse Tools(MAT) 工具, 可以直接 ...
 - 学会用Clang来进行内存泄露分析
		
最近项目出现了内存泄露的问题,对于PC x86平台来说,一点点的内存泄露往往不会出错,很难进行debug调试.这个时候我们可以用到苹果给我们带来的神器--Clang编译器来进行内存泄露分析检测,开关打 ...
 - nginx 内存池分析
		
最近nginx的源码刚好研究到内存池,这儿就看下nginx内存池的相关的东西. 一,为什么要使用内存池 大多数的解释不外乎提升程序的处理性能及减小内存中的碎片,对于性能优化这点主要体现在: (1)系统 ...
 - 《深入理解Java虚拟机》(六)堆内存使用分析,垃圾收集器 GC 日志解读
		
堆内存使用分析,GC 日志解读 重要的东东 在Java中,对象实例都是在堆上创建.一些类信息,常量,静态变量等存储在方法区.堆和方法区都是线程共享的. GC机制是由JVM提供,用来清理需要清除的对象, ...
 - Oracle内存全面分析
		
Oracle内存全面分析 Oracle的内存配置与oracle性能息息相关.而且关于内存的错误(如4030.4031错误)都是十分令人头疼的问题.可以说,关于内存的配置,是最影响Oracle性能的配置 ...
 - 【java基础 7】java内存区域分析及常见异常
		
本篇博客,主要是读书笔记总结,还有就是结合培训分享的总结,没有太多的技术含量! java 的自动内存管理机制,使得程序员不用为每一个new惭怍的对象写配对的delete/ free代码(回想起C++的 ...
 
随机推荐
- TF报错解决
			
一.import tensorflow #h5py/__init__.py:34: FutureWarning: Conversion of the second argument of issubd ...
 - flask 钩子函数
			
说明: before_request函数,就是一个装饰器,他可以把需要设置为钩子函数的代码放到视图函数执行之前执行 示例: from flask import Flask,url_for,redire ...
 - Python 排序和numpy排序,得到排序后索引序列(及源list的序列)
			
Python list 排序 & np list 排序 nums = [1.25, 0.98, 6.13, 7.62] li = np.array(nums) print(li) out = ...
 - 转 如何阅读TensorFlow源码
			
通过bazel学习之后,大概了解了TensorFlow的项目的源文件和描述文件. 下面是一篇不错的介绍,搬砖here. 在静下心来默默看了大半年机器学习的资料并做了些实践后,打算学习下现在热门的T ...
 - 4、JPA-EntityManager.merge()
			
EntityManager#merge merge() 用于处理 Entity 的同步.即数据库的插入和更新操作 merge的几种情况 1. 若传入的是一个临时对象 package jpa.test; ...
 - python 正则表达式re模块
			
#####################总结############## 优点: 灵活, 功能性强, 逻辑性强. 缺点: 上手难,旦上手, 会爱上这个东西 ...
 - STM32学习笔记:【004】USART串口通信
			
版本:STM32F429 Hal库v1.10 串口通信能够实现两块电路之间不同的通信,在开发中作为打印调试也是一门利器(printf重定向). 补充一点小知识: 1. weak修饰符修饰的函数,说明这 ...
 - HDU 1011(星河战队 树形DP)
			
题意是说在一个洞穴中有许多房间,每个房间中有一些虫子和大脑,这些房间之间用隧道相连形成一棵树,士兵们杀虫子的能力有限,也可以直接杀死虫子而不消耗士兵战斗力,但这样就无法得到房间中的大脑,士兵们不能走回 ...
 - python socket 编程
			
TCP IPv4 # server.py import socket import threading import time s = socket.socket(socket.AF_INET,soc ...
 - PHP的核心配置详解
			
1.PHP核心配置详解 代码在不同的环境下执行的结果也会大有不同,可能就因为一个配置问题,导致一个非常高危的漏洞能够利用:也可能你已经找到的一个漏洞就因为你的配置问题,导致你鼓捣很久都无法构造成功的漏 ...