内存改写coredump问题总结

        我们在开发过程中经常碰到coredump问题,其中有一类是内存数据被异常改写导致的,对于这一类问题处理起来其实是比较困难的。根据实际调试经验针对这类问题进行归纳总结,方便后续问题定位。

        内存改写导致coredump问题根据问题内存是否已被释放可以分为2类:低位内存越界改写和内存已被释放导致改写

低位内存越界改写

        对于这类情况,我们很好理解,就是出问题的堆内存对其下面的低地址部分内存越界改写导致自身数据异常。针对这类场景,通常被破坏的堆内存块的头结构被破坏,且较多连续的内存数据都被异常改写。我们可以根据被改写数据前后的特征字符串查找主动改写内存块的相关流程,相关方法可参考《疑难问题定位案例复盘(一)_局部变量越界_sy4331的博客-CSDN博客》相关章节。

内存已被释放导致改写

        当内存已经被释放后原流程还在继续使用将存在意想不到的结果,因此内存改写的第二种场景就是问题堆内存已经被释放了导致相关数据被改写。对于这种场景,根据问题内存是否已经被再次分配,可以分为两种类型:被释放的内存没有被再次分配出去和被释放的内存已经被再次分配出去

被释放的内存没有被再次分配出去

        当我们使用free接口把堆内存释放后,glibc的ptmalloc内存分配器将使用双向链表维护相关的空闲内存。具体措施是在分配给用户的堆内存的前8个字节处放置两个指针,分别指向空闲链表的前后节点。堆内存的头结构数据具体如下:

         根据上面分析可知,当堆内存被释放后,其原有用户数据部分的前8个字节将被改写为空闲双向链表的前后指针,此时若原有流程还在继续使用将产生意想不到的结果。

这时,使用该空闲内存块有两方:原有业务流程和glibc的ptmalloc分配器,它们都有可能因为改写数据造成对方产生coredump。也即这时有2种可能后果:

  1. 由于A模块继续使用该堆内存,特别是使用堆内存的前8个字节时(如当指针使用),将造成模块自身异常甚至产生coredump。
  2. A模块继续使用该堆内存,且改写了其前8个字节数据,即改写了空闲链表的前后指针。这样下次某个模块申请内存时,ptmalloc遍历打算使用该内存块前,因校验错误,ptmalloc将发送abort信号,申请内存模块产生coredump。

这类问题的特点是内存块的头结构数据正常,而用户可用内存的前8个字节看起来是两个堆内存地址,而其他部分内存数据基本正常。上述第2种场景可参考案例《疑难问题定位案例复盘(二)_sy4331的博客-CSDN博客》。

被释放的内存已经被再次分配出去

        当问题内存被释放又再次被分配出去时,由于新申请模块也会改写内存数据,从而导致流程异常。

         如上图所示,假设A模块先申请了堆内存,此后B模块释放了该内存,后续该内存又被重新分配给C模块。此时,A模块和C模块都在使用该部分堆内存,也即使用该堆内存有两方:A模块和C模块,它们都有可能因为改写数据造成对方产生coredump。这时也有2种可能后果:

  1. A模块继续使用该堆内存并改写了数据,造成C模块访问时数据异常,C模块产生coredump。
  2. C模块使用新申请的堆内存并改写了数据,造成A模块访问时数据异常,A模块产生coredump。

由于通常C模块是后获得内存的一方,其会覆盖原有A模块填充的数据,因此该堆内存出问题时往往填充的数据基本都是C模块的数据。所以我们在解析coredump时通常会看到2种场景。

  • 如果最终是上面的第1种情况,即A模块改写数据造成C模块产生coredump,此时我们解析coredump将看到该内存只有极少数部分数据被改写,大部分数据都正常,符合C模块预期。此时给我们的感觉似乎是有人在跳跃式改写。所以当我们碰到跳跃式改写时可以考虑这种场景。
  • 如果最终是上面的第2种情况,即C模块使用新申请的堆内存并改写了数据,造成A模块产生coredump,此时我们解析coredump将看到该内存绝大部分数据都被改写,基本都不符合A模块的预期。相较于上面场景,这种情况我们可能更容易联想到是内存被释放后又被分配出去改写造成coredump。

上述第2种场景可参考案例《疑难问题定位案例复盘(一)_局部变量越界_sy4331的博客-CSDN博客》。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android的coredump是指系统或应用程序由于某些错误而崩溃时,生成的一种二进制文件,包含了崩溃时的内存状态和寄存器信息等调试信息。这个文件可以帮助开发人员定位和解决崩溃问题。 在Android中,生成coredump的方式有多种,其中最常用的是通过adb命令行工具获取。具体步骤如下: 1. 连接Android设备到电脑,并打开调试模式。 2. 在电脑上打开命令行工具,输入以下命令: ``` adb shell ``` 3. 进入设备的shell环境后,输入以下命令: ``` su ``` 4. 获取正在运行的应用程序的PID号,例如: ``` ps | grep com.example.app ``` 5. 使用gdbserver启动应用程序,并将coredump写入指定文件中,例如: ``` gdbserver :5039 --attach <PID> --core <filename> ``` 其中,`:5039`是gdbserver监听的端口号,`<PID>`是应用程序的进程ID,`<filename>`是coredump文件的保存路径和文件名。 6. 在另一个终端窗口中,打开gdb调试工具,连接到gdbserver,并加载coredump文件,例如: ``` arm-linux-androideabi-gdb <path-to-binary> -ex "target remote :5039" -ex "core-file <filename>" ``` 其中,`<path-to-binary>`是应用程序的可执行文件路径,`<filename>`是coredump文件的路径和文件名。 7. 在gdb调试界面中,可以使用各种命令分析coredump文件的信息,例如查看寄存器状态、打印堆栈信息等。 需要注意的是,获取coredump文件需要root权限,而且对于系统级的crash,可能需要特殊的配置和调试工具才能捕获到完整的信息。此外,coredump文件可能会包含敏感信息,需要注意保密。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值