内存写越界导致破环堆结构引起的崩溃问题定位经验

简介:
前段时间开发的一个后端C模块上线后,线上出core,初始时,因为訪问压力不大,所以崩溃是上线3天左右出现的。当时用gdb跟进调用堆栈并检查源代码,发现出core位置的代码沒有啥问题。因为当时开发任务较重,且该模块不保存状态(崩溃重新启动不影响对外服务),所以沒有深入跟进。后来随着client版本号逐渐放量导致訪问压力上升,噩梦開始了。。。
该模块会不定时core掉,并且差点儿每次崩溃时的调用堆栈都不一样,关键是最后几层堆栈非常多都位于差点儿不可能出问题的代码中,比方库函数或厂里的公共库。
好在在众多core文件里发现规律:每次基本都是在对内存动态操作时挂掉,比方malloc/realloc/free/new/delete都引起了崩溃。并且幸运的是,崩溃进程还是输出了一些关键信息,比方以下这些(这些是在不同的崩溃时刻分别输出的):
*** glibc detected *** malloc(): memory corruption: 0x0000002a95c1ff10 ***
*** glibc detected *** double free or corruption (out): 0x0000000000f0d910 ***
*** glibc detected *** free(): invalid next size (normal): 0x0000002a96103b00 ***
*** glibc detected *** free(): invalid next size (fast): 0x0000000000f349d0 ***
*** glibc detected *** corrupted double-linked list: 0x0000002a95f062e0 ***
从上面的日志也能够看到,每次引起崩溃的直接原因都可能不同。用gdb又细致查看core文件发现,有时进程是收到SIGABRT信号后退出,有时又是收到SIGSEGV信号后退出。
由此,基本定位了崩溃原因:内存訪问越界导致破坏了heap的数据结构。用valgrind在线下环境启动进程,试图重现崩溃或定位越界訪问的代码,遗憾的是,脚本压了1个小时也没出现崩溃,而valgrind的输出报告也沒有越界代码位置的提示。
终于,细致检查源代码后发现,在某个回调函数中,new出来的buffer接收完通过http post方式发送过来的2进制数据后,我又多写了1行代码,相似于:recv_buf[data_len] = '\0',导致越界多写1个字节,终于引起各种莫名其妙的内存崩溃。
经验教训:
1)调用堆栈信息对定位问题帮助非常大,但也不可尽信。比方这次遇到的情况,每次出core的调用堆栈差点儿都不一样,并且最后几层栈帧都是不可能出现故障的库函数或久经考验的公司公共库,这样的情况下,思维须要跳出局部,在更高的层次寻找规律或原因
2)一旦定位崩溃属于堆内存读写越界问题,就细致检查自己的代码吧,因为库函数或公共库出问题的概率太小了,所以不要存在侥幸心理,这个时候,盲目的自信要不得

3)本来自觉得对内存操作已经非常小心了,没想到还是在想当然的瞬间写下犯错的代码,导致终于花费非常多时间和精力去“捉虫”。只是好在跟进崩溃的过程中添加了一点分析/定位问题的经验,也算有些收获吧。

本文转自博客园知识天地的博客,原文链接:内存写越界导致破环堆结构引起的崩溃问题定位经验,如需转载请自行联系原博主。


相关文章
|
16天前
|
存储 算法 Java
聊聊jvm的内存结构, 以及各种结构的作用
【10月更文挑战第27天】JVM(Java虚拟机)的内存结构主要包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和运行时常量池。各部分协同工作,为Java程序提供高效稳定的内存管理和运行环境,确保程序的正常执行、数据存储和资源利用。
43 10
|
16天前
|
存储 安全 程序员
内存越界写入
【10月更文挑战第13天】
31 4
|
16天前
|
Rust 安全 Java
内存数组越界
【10月更文挑战第14天】
20 1
|
16天前
|
Java 编译器 C++
内存越界读取
【10月更文挑战第13天】
24 2
|
17天前
|
存储 容器
内存越界访问(Out-of-Bounds Access)
【10月更文挑战第12天】
103 2
|
4月前
|
存储 设计模式 监控
运用Unity Profiler定位内存泄漏并实施对象池管理优化内存使用
【7月更文第10天】在Unity游戏开发中,内存管理是至关重要的一个环节。内存泄漏不仅会导致游戏运行缓慢、卡顿,严重时甚至会引发崩溃。Unity Profiler作为一个强大的性能分析工具,能够帮助开发者深入理解应用程序的内存使用情况,从而定位并解决内存泄漏问题。同时,通过实施对象池管理策略,可以显著优化内存使用,提高游戏性能。本文将结合代码示例,详细介绍如何利用Unity Profiler定位内存泄漏,并实施对象池来优化内存使用。
238 0
|
4月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
68 0
|
27天前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
48 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
2月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
153 4
Android性能测试——发现和定位内存泄露和卡顿
|
3月前
|
存储 安全 Java
JVM内存结构
这篇文章详细介绍了Java虚拟机(JVM)的内存结构,包括类的加载过程、类加载器的双亲委派机制、沙箱安全机制、程序计数器、Java栈、Java堆、本地方法和本地方法栈等关键组件及其作用。
JVM内存结构