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

2022-03-07 16:38:49 +08:00
 villivateur

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

设备平台:Xilinx Zynq 7010s

架构:Arm Cortex-A9

嵌入式操作系统:FreeRTOS

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

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

4245 次点击
所在节点    C++
22 条回复
CEBBCAT
2022-03-07 16:43:59 +08:00
嗯……换个板子呢?
villivateur
2022-03-07 16:49:35 +08:00
@CEBBCAT 一样的
3dwelcome
2022-03-07 16:50:29 +08:00
编译成 wasm 运行一下呢,应该没问题。
3dwelcome
2022-03-07 17:01:07 +08:00
忘了说,这里的 wasm 是指编译成后端微服务模式,不是浏览器里的模式。

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

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

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

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

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

真灵异事件还是少见。话说 gcc 是真难用,clang 从各方面秒杀。
3dwelcome
2022-03-07 17:43:23 +08:00
“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
2022-03-07 17:43:33 +08:00
ciichen
2022-03-07 19:39:26 +08:00
是不是正在计算浮点数的时候,刚好发生了 systick 线程切换,但是线程切换过程中,没有保存 /恢复浮点寄存器?
可以在浮点数运算中,停掉所有中断再看看有没有问题。
polaa
2022-03-07 19:51:13 +08:00
这种不是应该上 gdb 动态调试么
joshu
2022-03-07 20:06:35 +08:00
如果不考虑浮点数,我一般怀疑的方向有两个
内存访问越界,破坏了栈结构
在多线程上利用了 x86 上理所当然的 store-store 有序特性来做一些同步的操作,但 arm 上面我印象中 store-store 的执行并不是必然严格有序的(但单线程上保证结果正确)
geekzjj
2022-03-07 20:38:34 +08:00
@3dwelcome 我遇到的也是在 zynq 上,不过是另一个比较少见的实时操作系统。问题是浮点计算结果概率性为 0 ,也不知道是“打乱内存”,还是计算错误导致的。。
vance123
2022-03-07 22:02:51 +08:00
用过一个板子,调用 sprintf 就会清除内存,最后手写了一个 sprintf ,垃圾嵌入式

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/838643

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX