【crash】浮点除0堆损坏

2 篇文章 0 订阅
  • 摘要:工作中遇到一个crash,其现象真实的crash原因差别比较大,和我自身原本了解的只是冲突,因此在本片文档中简单描述下。
  • 关键字:除0、IEEE754

1 前情提要

  QA测试过程发现一个比较奇怪的crash,只会在特定机型特定素材上出现,而且出现crash的位置也比较诡异,具体堆栈如下:

0xxxxxxx split_buffer::construct_at_end
0xxxxxxx XXX::doProcess

  crash的具体原因是除0。

2 排查

  首先就是根据上面的堆栈分析可能crash的原因,因为是在vector在已经分配的内存上创建对象时崩溃,我们基本可以断定,这个vector的内存出现了问题。然后就去看代码排查调用链中可能导致堆损坏的地方(因为开发机无法复现,因此只能通过分析+日志来排查),在排查代码过程中发现了几处可能越界的操作以及除0。因为是堆损坏就朝着越界的方向去排查了,但是加了新的日志之后发现可能存在越界的代码实际上没有越界,而且实际崩溃的地方大概如下:

std::sort(vec.begin(), vec.end(), [](const bbox& a, const bbox& b){ 
    return a.p > b.p;   //崩溃的地方
});

  具体崩溃是在访问a时出现的,此时就有点儿匪夷所思了,崩溃堆栈是construct_at_end这个只有需要在vector中新建元素才会调用的函数,但是std::sort只涉及元素的交换(因为对应的vector比较小只有20个元素)。
  然后在排查是通过日志发现vector中的元素一部分的pinf,比较反常,因此排查了该值的计算来源发现是有double除0。然后将该处加了check后就不会崩溃了。
  到现在为止崩溃的原因基本已经确定了,除0UB导致的问题。

3 具体原因

  我个人一直以为除0一定会出现除0异常,所以最初并没有怀疑此处,而简单测试发现:

  • int整型除0一定会崩溃;
  • double除0会得到inf。

在这里插入图片描述
  IEEE754规定了浮点除0运算的结果为+INF或者-INF,但是C++标准明确规定了该行为未定义的,使用可能会导致UB。实际测试过程中发现只有低版本的机器浮点除0是不支持的,而新机器无论是windows还是Mac浮点除0编译器只会报warning但是结果是INF不会出错。

在这里插入图片描述

  具体原因是,C++并不强制编译器实现IEEE 754标准,因为可能受限于硬件平台无法实现。所以上面问题的结论是:

  1. 整数除0,必现除0异常;
  2. 浮点除0,不同编译器不同硬件平台现象不同不具备可移植性,应该按照C++的标准描述,是UB行为:
    1. C标准附件F(IEC 60559/IEEE754)定义了浮点除0的结果;
    2. 如果硬件的FLU且编译器支持IEC 559,那浮点除0返回+inf/-inf都是符合预期的:
      1. clang和msvc针对该行为都会报warning,能够正常运行得到inf。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值