现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

记一次踩内存事件

2019-10-30 22:31 工业·编程 ⁄ 共 1005字 ⁄ 字号 暂无评论

背景做各个模块集成,其中包含了文件管理、录像业务相关的库。在文件管理初始化时,应用层会指定数据根目录

现象:测试发现在执行特定操作时,目录失效,无法创建文件,日志大概这样  (NULL) /Movie/xxxx.MP4,好像是指定的根目录变空了。

检查一番, 没有进行去初始化, 跟文件管理库负责同事远程沟通了下,他在库里维护了一个指针,指向 应用 层设置的 目录字符串(这个方法当然不好,应该复制进去,后已修改),

在确认了应用 层没有改变这个 根目录的内容后, 可以肯定 这个指针在某个时间被修改为NULL。

用arm-xxxx-nm命令 检查相关文件管理 .a 静态库(没有使用.so库)的符号表, 发现数据段有指针RootDir及所在地址,为检测出是谁修改了这个指针变量,

编译好程序后 用arm-xxx-gdb启程序, 启动前watch RootDir,再执行触发异常的操作,然后可喜的看到了,的确有地方把这个指针修改成0了, 可悲的是watch停下来的时候,代码已经跑过去了,无法发现是哪处代码修改了它,跑了多次发现每次停下来的地方还不一样。

为什么不是修改这个变量的时候停下来,目前还不清楚,可能跟多线程有关。

问题要继续解决,这个时候只能暴力方法+打印了:

首先看这个RootDir变量在执行程序中的符号地址,用arm-xxx-nm  app 得到它的运行时地址,例如0x40008008,

然后分析触发变NULL的可能的代码路径, 在这些代码中插入多处打印,打印 *(unsigned int*)0x40008008 即RootDir存储的地址,看它在什么情况下变为0, 由非0变为0之间的代码 可能就是踩内存的地方。

(这里可能有个问题,插入打印语句后, RootDir的地址是可能变化的,所以编译后要用nm命令检测一遍RootDir的地址是否还是0x40008008,如果不是,则将打印语句中的0x40008008修改成新地址,再次编译,这之后应该就是一致的)

然后用类似二分法逐步缩小检测范围,直至定位到一个录像相关函数,在这个函数前RootDir有正常值,在这个函数执行后,RootDir记录的地址变0, 99%可以确定是这一函数引起的问题。

由于此函数是其它组件提供的库函数,交给相关负责人检查, 最终原因是数组操作越界,踩了一大片内存。为什么会踩到RootDir,这个是全局变量,编译进最终的可执行程序后,从地址上看,它和相关数组是相邻关系,然后被祸害了。。。

给我留言

留言无头像?