struct成员上的free()仅在Debug中导致Hardfault

时间:2019-06-13 13:57:17

标签: c arm gdb stm32 memory-alignment

我正在开发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

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

看着网上的 LDRDR 问题,我尝试将__attribute__((__packed__))添加到my_struct的定义中。 当通过指针/结构使用未对齐的内存访问时,应该强制编译器生成2x LDR

这样做,我在运行时不再需要Hardfault。好吧...

出于好奇,我想在修改后通过GDB检查地址,这很奇怪!没有任何变化(我的意思是关于地址),尽管有packed,但我还是再次遇到了 LDRD 指令并生成了我的Hardfault(但仅在GDB调试执行中)。

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

  • 为什么在调试器中看不到2x LDR
  • 更一般而言,为什么在没有GDB的情况下我都表现出相同的行为?
  • packed技巧是解决我这个问题的好方法吗?

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

2 个答案:

答案 0 :(得分:5)

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

  

为什么在调试器中看不到2xLDR?

由于free()在预编译的静态库中,因此不会重新编译。

  

更笼统地说,无论有没有GDB,为什么我没有相同的行为?

如果堆包含随机垃圾(由于未正确初始化或被一些无关的代码覆盖),则在将事物连接到板上或从板上断开连接时,您可能会遇到不同的垃圾。或每当某些环境因素改变时。

  

packed技巧是解决我这个问题的好方法吗?

不,它只是靠运气掩盖了问题。堆烂了,所有赌注都关闭了。

答案 1 :(得分:-1)

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

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

向我们展示一切。 malloc的结果,实际代码和链接脚本。