结构成员上的 free() 仅在调试中导致 Hardfault

free() on struct member causes Hardfault only in Debug

我正在研究 STM32F7。 当我在以下(简化的)代码中点击 free() 时会触发硬故障:

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

CFSR0x8200 并且 MMFARBFAR 寄存器都包含 0x5F0FE9D8

看网上的LDRDR问题,尝试在my_struct定义中加入__attribute__((__packed__))。 当通过 pointers/structures.

使用未对齐的内存访问时,应该强制编译器生成 2xLDR

通过这样做,我在 运行 时不再有 Hardfault。好的...

出于好奇,我想通过GDB查看修改后的地址,惊喜!没有任何变化(我的意思是地址),我最终再次点击 LDRD 指令,尽管 packed,并生成我的 Hardfault(但仅在 GDB 调试执行中) .

我在删除属性后启动了一个新的 运行 并比较了 MMFARBFAR 寄存器的值,当我不在 GDB 中时,我得到了 0x41AFFE60

P.S。我正在 运行ning FreeRTOS 并将 configCHECK_FOR_STACK_OVERFLOW 定义为 2 和 configASSERT,没有触发。

0x5F0FE9D80x41AFFE60都在STM32F7内存映射(参考手册第2章)中标记为保留。这意味着 堆已损坏

Why can't I see the 2xLDR in the debugger ?

因为free()在预编译的静态库中,所以没有重新编译。

More generally, why don't I have the same behavior with and without GDB ?

如果堆包含随机垃圾,要么是因为它没有正确初始化,要么是被一些不相关的代码覆盖,当您将东西连接到电路板或从板上断开连接时,您可能会得到一些不同的垃圾。或者每当某些环境因素发生变化时。

Is the packed trick is the good solution for my issue ?

不,它只是侥幸地设法隐藏了问题。对于损坏的堆,所有赌注都将取消。

您从错误的一端开始调试。你检查过 malloc 返回的值了吗?可能不会。

如果地址无效,通常意味着您的链接描述文件有误。

向我们展示一切。 malloc 的结果、实际代码和链接描述文件。