V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
villivateur
V2EX  ›  C++

灵异事件后续: C++代码里面进行浮点数计算就会破坏内存

  •  
  •   villivateur ·
    villivateur · 2022-03-07 16:38:49 +08:00 · 3921 次点击
    这是一个创建于 753 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言: https://v2ex.com/t/837189

    设备平台:Xilinx Zynq 7010s

    架构:Arm Cortex-A9

    嵌入式操作系统:FreeRTOS

    现象:只要在程序中(不管是中断还是普通线程)执行浮点数操作(乘除),另一个线程里面的 TCP/IP 协议栈缓存区数据就会中等概率被破坏。

    使用的平台有双精度 FPU ,并且在 g++ 里面已经启用,尝试修改 g++ 关于 FPU 的编译参数,无效。

    第 1 条附言  ·  2022-03-08 10:27:28 +08:00
    感谢 V 友帮忙。

    具体原因是:在中断里使用 FPU ,需要先将 FPU 的寄存器压栈。

    具体解决方案:在调用 FPU 的中断里面添加以下汇编代码即可:

    ```c
    void IntHook()
    {
    __asm("VPUSH.64 {D0-D15}");
    // other code
    __asm("VPOP.64 {D0-D15}");
    }
    ```

    @geekzjj @Hconk @3dwelcome @Hconk
    22 条回复    2022-03-08 16:15:05 +08:00
    CEBBCAT
        1
    CEBBCAT  
       2022-03-07 16:43:59 +08:00
    嗯……换个板子呢?
    villivateur
        2
    villivateur  
    OP
       2022-03-07 16:49:35 +08:00
    @CEBBCAT 一样的
    3dwelcome
        3
    3dwelcome  
       2022-03-07 16:50:29 +08:00 via Android
    编译成 wasm 运行一下呢,应该没问题。
    3dwelcome
        4
    3dwelcome  
       2022-03-07 17:01:07 +08:00
    忘了说,这里的 wasm 是指编译成后端微服务模式,不是浏览器里的模式。

    就是在普通操作系统里可运行,类似于 arm 版本服务器的虚拟机模式来运行。
    duke807
        5
    duke807  
       2022-03-07 17:08:46 +08:00 via Android
    這種問題要靠自己慢慢查,多解決幾次,你才能成為高手

    嵌入式不建議用 c++,查底層問題比較麻煩

    你先對比一下 開與不開 硬浮點的現象是否相同。
    yehoshua
        6
    yehoshua  
       2022-03-07 17:15:35 +08:00 via Android
    嵌入式…很多时候出问题和你的板子 /平台有关系,特别是这种固定大概率出现的问题。
    villivateur
        7
    villivateur  
    OP
       2022-03-07 17:16:34 +08:00
    @duke807 很遗憾,我这个 FreeRTOS 平台没法关闭硬 FPU ,但我试过 -mfloat-abi=softfp 和 -mfloat-abi=hard 都不行
    shyrock
        8
    shyrock  
       2022-03-07 17:21:01 +08:00
    当初放弃 C++的一个原因就是觉得内存管理太浪费精力。
    一般来说这种高复现率的问题我会推荐用代码屏蔽大法,先屏蔽 50%,看看能不能复现,不能则再屏蔽剩下的 50%,最后你就会发现破坏内存编辑的操作是哪个。
    geekzjj
        9
    geekzjj  
       2022-03-07 17:22:21 +08:00 via Android   ❤️ 1
    同样的平台,不同的系统,以前遇到过差不多一样的坑。。当时规避的方式的方法是,做浮点的时候禁用一切引起上下文切换的操作,包括禁中断😂
    villivateur
        10
    villivateur  
    OP
       2022-03-07 17:33:15 +08:00
    @shyrock 已经用了这个方案了,最后定位到是浮点数运算的问题
    Hconk
        11
    Hconk  
       2022-03-07 17:34:50 +08:00   ❤️ 1
    这个问题和你遇到的情况有没有关系,https://support.xilinx.com/s/article/71079?language=en_US
    shyrock
        12
    shyrock  
       2022-03-07 17:36:00 +08:00
    @villivateur #10 到了这一步,可以找到被破坏的堆栈地址,单步执行看看浮点运算前后这个地址的数据有什么变化。。。
    3dwelcome
        13
    3dwelcome  
       2022-03-07 17:37:31 +08:00
    @geekzjj 真有那么神奇吗?是不是驱动设计存在问题。

    以前 dx 开发时,也遇到过需要设置_controlfp FPU 的地方,gcc 里是 control87 ,但最多是浮点计算错误,并不会把给内存给打乱。

    如果内存乱,不是堆栈渗出,就是数学库的问题(比如 int64 计算都是需要额外库的,也许没考虑多线程)。

    真灵异事件还是少见。话说 gcc 是真难用,clang 从各方面秒杀。
    3dwelcome
        14
    3dwelcome  
       2022-03-07 17:43:23 +08:00   ❤️ 5
    “Some GCC libraries optimise memory copy and memory set (and possibly other) functions by making use of the wide floating point registers. Therefore, by default, any task that uses functions such as memcpy(), memcmp() or memset(), or uses a FreeRTOS API function such as xQueueSend() which itself uses memcpy(), will inadvertently corrupt the floating point registers.”

    还真是 GCC 的锅。。。
    Hconk
        15
    Hconk  
       2022-03-07 17:43:33 +08:00   ❤️ 1
    ciichen
        16
    ciichen  
       2022-03-07 19:39:26 +08:00 via Android
    是不是正在计算浮点数的时候,刚好发生了 systick 线程切换,但是线程切换过程中,没有保存 /恢复浮点寄存器?
    可以在浮点数运算中,停掉所有中断再看看有没有问题。
    polaa
        17
    polaa  
       2022-03-07 19:51:13 +08:00
    这种不是应该上 gdb 动态调试么
    joshu
        18
    joshu  
       2022-03-07 20:06:35 +08:00
    如果不考虑浮点数,我一般怀疑的方向有两个
    内存访问越界,破坏了栈结构
    在多线程上利用了 x86 上理所当然的 store-store 有序特性来做一些同步的操作,但 arm 上面我印象中 store-store 的执行并不是必然严格有序的(但单线程上保证结果正确)
    geekzjj
        19
    geekzjj  
       2022-03-07 20:38:34 +08:00 via Android
    @3dwelcome 我遇到的也是在 zynq 上,不过是另一个比较少见的实时操作系统。问题是浮点计算结果概率性为 0 ,也不知道是“打乱内存”,还是计算错误导致的。。
    vance123
        20
    vance123  
       2022-03-07 22:02:51 +08:00
    用过一个板子,调用 sprintf 就会清除内存,最后手写了一个 sprintf ,垃圾嵌入式
    LANB0
        21
    LANB0  
       2022-03-08 15:14:00 +08:00
    之前碰到过类似问题,64 位平台 tx1 设备上,某一特定位置,只要一操作指针类型转换就崩溃,前面加条 printf 打印就正常。后来排查是内存非对齐访问触发了对齐异常
    kingcanfish
        22
    kingcanfish  
       2022-03-08 16:15:05 +08:00
    @shyrock 经典二分了属于是
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5312 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 09:08 · PVG 17:08 · LAX 02:08 · JFK 05:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.