我正在开发STM32F7。
当我在以下(简化的)代码中按下free()
时会触发一次Hardfault:
typedef struct
{
uint8_t size;
uint8_t* data;
}my_struct;
void foo()
{
my_struct msg;
msg.size = 5;
msg.data = malloc(msg.size);
if(msg.data != NULL)
{
free(msg.data); // Hardfault
}
}
在free()
中逐步使用GDB,我发现了引起Hardfault的汇编指令:
ldrd r1, r3, [r5, #8]
r5
的值为0x5F0FE9D0
CFSR
为0x8200
,并且MMFAR
和BFAR
寄存器都包含0x5F0FE9D8
,
看着网上的 LDRDR 问题,我尝试将__attribute__((__packed__))
添加到my_struct
的定义中。
当通过指针/结构使用未对齐的内存访问时,应该强制编译器生成2x LDR 。
这样做,我在运行时不再需要Hardfault。好吧...
出于好奇,我想在修改后通过GDB检查地址,这很奇怪!没有任何变化(我的意思是关于地址),尽管有packed
,但我还是再次遇到了 LDRD 指令并生成了我的Hardfault(但仅在GDB调试执行中)。>
在删除属性并比较MMFAR
和BFAR
寄存器的值之后,我启动了新的运行,当我不在GDB中时,我得到了0x41AFFE60
packed
技巧是解决我这个问题的好方法吗? P.S。我正在运行FreeRTOS,并且已将configCHECK_FOR_STACK_OVERFLOW
定义为2和configASSERT
,没有任何触发。
答案 0 :(得分:5)
0x5F0FE9D8
和0x41AFFE60
在STM32F7存储器映射(参考手册的第2章)中都标记为保留。这意味着堆已损坏。
为什么在调试器中看不到2xLDR?
由于free()
在预编译的静态库中,因此不会重新编译。
更笼统地说,无论有没有GDB,为什么我没有相同的行为?
如果堆包含随机垃圾(由于未正确初始化或被一些无关的代码覆盖),则在将事物连接到板上或从板上断开连接时,您可能会遇到不同的垃圾。或每当某些环境因素改变时。
packed
技巧是解决我这个问题的好方法吗?
不,它只是靠运气掩盖了问题。堆烂了,所有赌注都关闭了。
答案 1 :(得分:-1)
您从错误的一端开始调试。您是否检查了malloc返回的值?可能不会。
如果地址无效,通常表示您的链接描述文件有误。
向我们展示一切。 malloc的结果,实际代码和链接脚本。