工具链更新后带有浮点数的 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)解决了同样的问题,是创建我自己的浮点数到字符串的转换函数。它显着提高了性能(不再 malloc
s),硬故障错误消失了,我将每个任务的堆大小调整到我真正需要的大小。
在 https://github.com/mpaland/printf
的帮助下,我终于能够获得我的固件 运行
即我刚刚在我的代码中去掉了 Newlib 的 sprintf()。
我有一个开源项目 (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)解决了同样的问题,是创建我自己的浮点数到字符串的转换函数。它显着提高了性能(不再 malloc
s),硬故障错误消失了,我将每个任务的堆大小调整到我真正需要的大小。
在 https://github.com/mpaland/printf
的帮助下,我终于能够获得我的固件 运行即我刚刚在我的代码中去掉了 Newlib 的 sprintf()。