struct 成员上的 free() 仅在 Debug 中导致 Hardfault
Posted
技术标签:
【中文标题】struct 成员上的 free() 仅在 Debug 中导致 Hardfault【英文标题】:free() on struct member causes Hardfault only in Debug 【发布时间】:2019-06-13 13:57:17 【问题描述】:我正在研究 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__))
。
当通过指针/结构使用未对齐的内存访问时,它应该强制编译器生成 2xLDR。
通过这样做,我在运行时不再有硬故障。好的...
出于好奇,我想在修改后通过 GDB 检查地址,结果大吃一惊!没有任何变化(我的意思是地址),尽管packed
,我最终还是再次点击了 LDRD 指令,并生成了我的 Hardfault(但仅在 GDB 调试执行中)。
我在删除属性后启动了一个新的运行并比较了MMFAR
和BFAR
寄存器的值,当我不在GDB时我得到0x41AFFE60
packed
技巧是解决我问题的好方法吗?
附:我正在运行 FreeRTOS,并将 configCHECK_FOR_STACK_OVERFLOW
定义为 2 和 configASSERT
,没有任何触发。
【问题讨论】:
正如其他人所指出的,您可能会遇到一些内存损坏。这可能是堆栈溢出到堆或其他静态变量中,具体取决于您的内存布局。但这只是猜测。我建议你仔细检查你的内存映射。关于(打包)属性,我不确定这会有什么帮助。如果有的话,恕我直言,这会让事情变得更糟。 【参考方案1】:0x5F0FE9D8
和 0x41AFFE60
在 STM32F7 内存映射(参考手册的第 2 章)中都标记为保留。这意味着堆已损坏。
为什么我在调试器中看不到 2xLDR?
因为free()
在预编译的静态库中,所以不会重新编译。
更一般地说,为什么在使用和不使用 GDB 时我的行为不同?
如果堆包含随机垃圾,或者因为它没有正确初始化,或者被一些不相关的代码覆盖,当你连接到板或从板上断开连接时,你可能会得到一些不同的垃圾。或者当某些环境因素发生变化时。
packed
技巧是解决我问题的好方法吗?
不,它只是靠运气设法隐藏了问题。有了损坏的堆,所有的赌注都没有了。
【讨论】:
【参考方案2】:您从错误的一端开始调试。你检查过malloc返回的值吗?可能不是。
如果地址无效,通常意味着您的链接描述文件有误。
向我们展示一切。 malloc 的结果、实际代码和链接描述文件。
【讨论】:
我检查了 malloc 返回的地址,它在链接描述文件中定义的堆的有效范围内。不幸的是,由于我正在处理专有项目,因此我无法分享实际代码... 如果不显示真实代码,就没有任何帮助。您认为有人对使用 malloc 的 uC 代码感兴趣吗? 我并不是说这很重要或其他什么,我只是遵守 NDA。此外,我不希望 SO 调试我的代码,我只需要指针,你给了一些 :)以上是关于struct 成员上的 free() 仅在 Debug 中导致 Hardfault的主要内容,如果未能解决你的问题,请参考以下文章
malloc struct vs. 的“成员”当结构非常简单时,整个结构
仅在一个构造函数上的类成员初始化程序中的隐式常量转换 [-Werror=overflow] 溢出
内存管理概述内存分配与释放地址映射机制(mm_struct, vm_area_struct)malloc/free 的实现