工具链更新后带有浮点数的 sprintf() 硬故障

Hard fault on sprintf() with float after toolchain update

我有一个开源项目 (https://github.com/WhiteFossa/yiff-l),我在其中使用了 STM32F103 MCU。

在固件中我有很多带有浮点参数的sprintf,例如:

char buffer[32];
sprintf(buffer, "Power: %.1fW", power);

我曾经使用很老的 arm-none-eabi xpack 很长一段时间(IIRC 是 9.3.1 版本),一切都很好。

然后我不得不重新安装我的软呢帽,当然我有一个更新版本的 arm-none-eabi。 我的项目停止编译,我修复了一些代码,现在它再次编译,但在任何带有 float 的 sprintf 上都会产生硬故障。

如果我排除 -u _printf-float 链接器标志,那么硬错误就消失了,但当然我的字符串中没有浮点表示。

我很确定问题不在我的代码中,我什至尝试将 sprintf 作为 main() 的第一行,但仍然有同样的问题。

什么会导致这种奇怪的行为?我该如何调试它? (从未用于调试 ARM 反汇编)。

P.s。我尝试安装较旧的 arm-none-eabi xpacks,但没有任何运气 - 问题仍然存在。

P.p.s。我尝试过优化 settings/changed 发布以进行调试,反之亦然,在 sections.ld 中设置 4 倍以上的堆栈 - 一切都没有成功。

任何帮助将不胜感激。

看到这段代码我唯一想到的就是power的值很大:

double power = 11111111111111111111111111111111111111111111.2;
char buffer[32];
sprintf(buffer, "Power: %.1fW", power);

printf("%s\n", buffer);

如果不是这种情况,那么其他地方一定有一些 UB

查找硬故障很复杂,而且常常令人沮丧。在大多数情况下,我遇到了硬故障,我只是跳到使用一个硬件调试器。我用于 Cortex-M 设备的是 Segger 的 J-Tag Pro。还有其他型号,便宜,便宜很多。

什么会导致这种奇怪的行为? 正如您所确定的那样,当 sprintf 被禁用时,您的问题就被掩盖了。我最好的猜测是,这很可能是由输出缓冲区中的缓冲区溢出或错误的库代码引起的。一些 sprintf 实现使用堆内存分配并且不检查 NULL returns。有一些使用 Fee-RTOS 的 BSP 实现需要更多调整以启用动态内存管理。

如果即使使用大缓冲区也出现硬故障,那么这可能是由 sprintf 中的内部内存分配引起的。您可以尝试使用其他库。据我所知,newlib-nano 在某些情况下会导致此错误。

在某些情况下,需要增加调用 sprintf/snprintf 的任务的堆栈大小和全局堆大小。

我如何调试它? 可能唯一的解决方案是结合使用一个硬件调试器和一个完整的 IDE,例如 Eclipse。 Here is a bit of information that will give you some guidelines. The J-Link Edu Mini 硬件调试器的价格相当实惠,但您周围还有更多选项也会对您有所帮助。

我用类似的 CPU(Kinetis K22,来自以前的飞思卡尔现在的 NxP)解决了同样的问题,是创建我自己的浮点数到字符串的转换函数。它显着提高了性能(不再 mallocs),硬故障错误消失了,我将每个任务的堆大小调整到我真正需要的大小。

https://github.com/mpaland/printf

的帮助下,我终于能够获得我的固件 运行

即我刚刚在我的代码中去掉了 Newlib 的 sprintf()。