C++-如何排查内存写坏

本文介绍了一种使用mprotect和信号量处理方法来排查和定位C++中内存写坏问题的技术。通过将内存区域设置为特定保护模式,如只读,当模式被破坏时会触发SIGSEGV信号,进而捕获并分析堆栈调用,帮助开发者快速找到内存错误源。同时,文章提供了使用mmap进行内存映射的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存写坏问题

c++内存写坏问题,有很多原因造成,包括野指针、指针越界、并发场景等,出现很难排查,有很多内存分析工具可以使用,比如Valgrind1等很多方式
本文总结一种容易排查定位的方法:
mprotect+信号量处理【比如利用backtrace打印堆栈调用方式】,从而定位到哪里写坏内存

mprotect

mprotect是一种系统调用,mprotect
简单而言,mprotec可以指定一块内存保护为指定的模式,比如只读模式,这样当有场景破坏该模式的时候,就可以发送信号量SIGSEGV,这时候程序中捕获SIGSEGV,就可以获取到相关信息

函数原型

#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);

其中addr和len指定保护的内存区域,其中prot是模式,比如

   PROT_NONE  The memory cannot be accessed at all.
   PROT_READ  The memory can be read.
   PROT_WRITE The memory can be modified.
   PROT_EXEC  The memory can be executed.

注意事项

其中需要注意的一点,mprotect要求保护的addr需要内存地址页对齐。因此如果保护的地址不是内存地址页对齐,需要改造比如填充保证对齐,或者使用mmap分配内存,保证一定是对齐的

mmap

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。具体可以参考认真分析mmap:是什么 为什么 怎么用

函数原型

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

例子

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static int alloc_size;
static char* memory;

void segv_handler(int signal_number)
{
  printf ("memory accessed!\n");
  mprotect (memory, alloc_size, PROT_READ | PROT_WRITE);
}

int main ()
{
  int fd;
  struct sigaction sa;

  // 初始化segv_handler为SIGSEGV的句柄
  memset (&sa, 0, sizeof (sa));
  sa.sa_handler = &segv_handler;
  sigaction (SIGSEGV, &sa, NULL);

  // 使用映射/dev/zero分配内存页。最初映射的内存为只写
  alloc_size = getpagesize();
  fd = open ("/dev/zero", O_RDONLY);
  // 分配内存
  memory = static_cast<char *>(mmap (NULL, alloc_size, PROT_WRITE, MAP_PRIVATE, fd, 0));
  close (fd);
  // 写页来获得一个私有复制
  memory[0] = 0;
  // 使内存为不可写
  mprotect (memory, alloc_size, PROT_READ);

  // 写分配内存区域
  memory[0] = 1;

  // 释放内存
  printf ("free mem\n");
  munmap (memory, alloc_size);

  return 0;
}

g++ main.cpp -o main
执行后,./main
./main
memory accessed!
free mem


  1. 应用 Valgrind 发现 Linux 程序的内存问题 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值