mmap 映射的内存访问出错

现象

把一个打开的文件描述符,通过mmap映射到一片内存区间,对这块区间进行读写,长时间运行后出现访存错误 SIGBus Error, GDB分析相应的core出现一些内存空间不可用的错误。

问题分析

参考man mmap , 在出现下列情况下,会出错:

ERRORS
       EBADF  fd is not a valid file descriptor (and MAP_ANONYMOUS was not set).

       EACCES A  file  descriptor  refers  to a non-regular file.  Or MAP_PRIVATE was requested, but fd is not open for reading.  Or
              MAP_SHARED was requested and PROT_WRITE is set, but fd is not open in read/write (O_RDWR) mode.  Or PROT_WRITE is set,
              but the file is append-only.

       EINVAL We don‘t like start or length or offset.  (E.g., they are too large, or not aligned on a PAGESIZE boundary.)

       ETXTBSY
              MAP_DENYWRITE was set but the object specified by fd is open for writing.

       EAGAIN The file has been locked, or too much memory has been locked.

       ENOMEM No memory is available, or the process‘s maximum number of mappings would have been exceeded.

       ENODEV The underlying filesystem of the specified file does not support memory mapping.

       Use of a mapped region can result in these signals:

       SIGSEGV
              Attempted write into a region specified to mmap as read-only.

       SIGBUS Attempted  access  to a portion of the buffer that does not correspond to the file (for example, beyond the end of the
              file, including the case where another process has truncated the file).
根据上面的说明,可以看到出现SIGBUS错误的时候,要么访问的buffer 不在文件范围之内,或者所映射的文件已经被truncate了。但笔者碰到的错误并不是调用mmap碰到的,而是在访问buffer 过程中碰到的。 那该怎么分析呢?

解决方法和验证

首先理清了下笔者所在的系统的上下文环境,弄清楚了涉及到mmap 的文件及其内存区间的使用方式。接着根据异常的core ,用GDB去看访问那个文件的多个线程的堆栈,居然发现:一个线程在访问mmap的buffer,另外一个线程居然还在重新打开那个文件!对着异常日志检查,确实是有个线程重新打开了一个已经mmap的文件。

马上加了下防御的代码,重新跑起来了测试,这个问题彻底消失了。

总结

发现mmap 异常的问题,需要充分结合?core的多个线程堆栈进行分析排查,才能解决问题。

原文地址:https://blog.51cto.com/xiamachao/2467971

时间: 2024-10-27 00:56:44

mmap 映射的内存访问出错的相关文章

细说linux IPC(三):mmap系统调用共享内存

前面讲到socket的进程间通信方式,这种方式在进程间传递数据时首先需要从进程1地址空间中把数据拷贝到内核,内核再将数据拷贝到进程2的地址空间 中,也就是数据传递需要经过内核传递.这样在处理较多数据时效率不是很高,而让多个进程共享一片内存区则解决了之前socket进程通信的问题.共享内存 是最快的进程间通信 ,将一片内存映射到多个进程地址空间中,那么进程间的数据传递将不在涉及内核.        共享内存并不是从某一进程拥有的内存中划分出来的:进程的内存总是私有的.共享内存是从系统的空闲内存池中

C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)

白杨 http://baiy.cn 在我几年前开始写<C++编码规范与指导>一文时,就已经规划着要加入这样一篇讨论 C++ 异常机制的文章了.没想到时隔几年以后才有机会把这个尾巴补完 :-). 还是那句开场白:“在恰当的场合使用恰当的特性” 对每个称职的 C++ 程序员来说都是一个基本标准.想要做到这点,就必须要了解语言中每个特性的实现方式及其时空开销.异常处理由于涉及大量底层内容,向来是 C++ 各种高级机制中较难理解和透彻掌握的部分.本文将在尽量少引入底层细节的前提下,讨论 C++ 中这一

linux mmap 映射文件

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 函数功能:把文件内容映射到一段内存上(虚拟内存),通过对这段内存的读取和修改,实现对文件的读取和修改. 参数说明 addr:指定映射的起始地址,通常设为NULL(表示由系统指定). length:代表将文件中多大的部分映射到内存. port:映射区域的保护方式.可以为一下几种方式的组合: PROT_EXEC   映射区域可以被执行 P

Linux内核内存管理-内存访问与缺页中断【转】

转自:https://yq.aliyun.com/articles/5865 摘要: 简单描述了x86 32位体系结构下Linux内核的用户进程和内核线程的线性地址空间和物理内存的联系,分析了高端内存的引入与缺页中断的具体处理流程.先介绍了用户态进程的执行流程,然后对比了内核线程,引入高端内存的概念,最后分析了缺页中断的流程. 用户进程 fork之后的用户态进... 简单描述了x86 32位体系结构下Linux内核的用户进程和内核线程的线性地址空间和物理内存的联系,分析了高端内存的引入与缺页中断

高端内存映射之kmap持久内核映射--Linux内存管理(二十)

1 高端内存与内核映射 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供了其他函数用于将ZONE_HIGHMEM页帧显式映射到内核空间, 这些函数与vmalloc机制无关. 因此, 这就造成了混乱. 而在高端内存的页不能永久地映射到内核地址空间. 因此, 通过alloc_pages()函数以__GFP_HIGHMEM标志获得的内存页就不可能有逻辑地址. 在x86_32体系结构总,

汇编学习笔记--寄存器(内存访问 1)

内存访问首先要有地址,8086pc中的段地址存放在 ds 寄存器中(ds 和 cs是不一样的,cs是定位地址用于读取内存中的指令或者数据,而ds是读取内存中的数据时使用,下面我们会明白区别) 将内存中的数据写入寄存器: mov bx,1000H mov ds,bx mov al,[0] 第一句是把1000H给bx(寄存器),第二句把bx中的值给ds(段地址寄存器),第三句从1000:0H中读取数据给al(寄存器ax的低8位):至于为什么不直接把段地址1000H给ds,这是8086硬件设计的问题,

GNU C - 关于8086的内存访问机制以及内存对齐(memory alignment)

一.为什么需要内存对齐? 无论做什么事情,我都习惯性的问自己:为什么我要去做这件事情? 是啊,这可能也是个大家都会去想的问题, 因为我们都不能稀里糊涂的或者.那为什么需要内存对齐呢?这要从cpu的内存访问机制说起. 为了了解清楚cpu的内存访问机制,昨天整晚都在查找资料,但是还是找不到很好的介绍资料.后来只是找到了相关 的一些介绍的博客. 这些博客中大多都是以介绍内存对齐为主要目的,然后顺带着说一下cpu的内存访问机制,所以 找不到权威的资料,后来听说<<汇编语言编程艺术>>这本书

内存泄露与内存访问越界

内存泄露 在堆上分配的内存,没有及时释放掉,以便后面其它地方可以重用.在C/C++中,内存管理器不会帮你自动回收不再使用的内存.如果你忘了释放不再使用的内存,这些内存就不能被重用,就造成了所谓的内存泄露. 一两处内存泄露通常不至于让程序崩溃,也不会出现逻辑上的错误,当然了,量变会产生质变,一旦内存泄露过多以致于耗尽内存,后续内存分配将会失败,程序可能因此而崩溃. 内存访问越界,使用的内存 超出了 向系统申请了一块内存,覆盖该空间之后的一段存储区域,导致系统异常. 常见原因: 1 写越界,又叫缓冲

3.寄存器(内存访问)

寄存器(内存访问) 看到标题才发现,第二章是寄存器直接与常量(数字)进行交互 内存中字的存储假设读取字节(流)为从左向右读对字的处理为从又向左正是因为不同,所以才会发问吧 DS与偏移地址:通用的获取地址的方式(CS:IP这个是给程序用的)类似于通用寄存器,但不能使用move ds,1:单纯的说指令太少了的话也对(jmp 不也就省2指令,还多出N多种),应该是跟指令流程相关(intel 指令手册,我的第一反应其实是是使用灵活的方式进行修改还是使用通用的方式进行修改...小学语文学太多了,自动升华)