结构成员上的 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
CFSR
是 0x8200
并且 MMFAR
和 BFAR
寄存器都包含 0x5F0FE9D8
、
看网上的LDRDR问题,尝试在my_struct
定义中加入__attribute__((__packed__))
。
当通过 pointers/structures.
使用未对齐的内存访问时,应该强制编译器生成 2xLDR
通过这样做,我在 运行 时不再有 Hardfault。好的...
出于好奇,我想通过GDB查看修改后的地址,惊喜!没有任何变化(我的意思是地址),我最终再次点击 LDRD 指令,尽管 packed
,并生成我的 Hardfault(但仅在 GDB 调试执行中) .
我在删除属性后启动了一个新的 运行 并比较了 MMFAR
和 BFAR
寄存器的值,当我不在 GDB 中时,我得到了 0x41AFFE60
- 为什么我在调试器中看不到 2xLDR?
- 更一般地说,为什么在使用和不使用 GDB 时我的行为不同?
packed
技巧是解决我的问题的好方法吗?
P.S。我正在 运行ning FreeRTOS 并将 configCHECK_FOR_STACK_OVERFLOW
定义为 2 和 configASSERT
,没有触发。
0x5F0FE9D8
和0x41AFFE60
都在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 的结果、实际代码和链接描述文件。
我正在研究 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
CFSR
是 0x8200
并且 MMFAR
和 BFAR
寄存器都包含 0x5F0FE9D8
、
看网上的LDRDR问题,尝试在my_struct
定义中加入__attribute__((__packed__))
。
当通过 pointers/structures.
通过这样做,我在 运行 时不再有 Hardfault。好的...
出于好奇,我想通过GDB查看修改后的地址,惊喜!没有任何变化(我的意思是地址),我最终再次点击 LDRD 指令,尽管 packed
,并生成我的 Hardfault(但仅在 GDB 调试执行中) .
我在删除属性后启动了一个新的 运行 并比较了 MMFAR
和 BFAR
寄存器的值,当我不在 GDB 中时,我得到了 0x41AFFE60
- 为什么我在调试器中看不到 2xLDR?
- 更一般地说,为什么在使用和不使用 GDB 时我的行为不同?
packed
技巧是解决我的问题的好方法吗?
P.S。我正在 运行ning FreeRTOS 并将 configCHECK_FOR_STACK_OVERFLOW
定义为 2 和 configASSERT
,没有触发。
0x5F0FE9D8
和0x41AFFE60
都在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 的结果、实际代码和链接描述文件。