free() on struct member causes Hardfault only in Debug

Viewed 188

I am working on a STM32F7. A Hardfault is triggered when I hit the free() in the following (simplified) code:

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
     }
}

Going step by step with GDB in the free() I found the assembly instruction that caused the Hardfault:

ldrd    r1, r3, [r5, #8]

The value of r5 is 0x5F0FE9D0

CFSR is 0x8200 and both MMFAR and BFAR registers contains 0x5F0FE9D8,

Looking at LDRDR problems on the net, I tried to add __attribute__((__packed__)) to my_struct definition. It is supposed to force the compiler to generate 2xLDR instead when using unaligned memory access via pointers/structures.

By doing that, I no longer have an Hardfault at runtime. OK...

Out of curiosity, I wanted to inspect the addresses via GDB after this modification, and surprise ! Nothing changes (I mean about the addresses) and I ends up hitting the LDRD instruction again, despite the packed, and generating my Hardfault (but only in GDB-debug execution).

I launched a new run after removing the attribute and compared the value of MMFAR and BFAR registers and when I am not in GDB I got 0x41AFFE60

  • Why can't I see the 2xLDR in the debugger ?
  • 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 ?

P.S. I am running FreeRTOS and have defined configCHECK_FOR_STACK_OVERFLOW to 2 and configASSERT, nothing triggers.

2 Answers

Both 0x5F0FE9D8 and 0x41AFFE60 are marked as reserved in the STM32F7 memory map (chapter 2 of the Reference Manual). It means that the heap is corrupted.

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

Because free() is in a precompiled static library, it's not recompiled.

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

If the heap contains random junk, either because it's not initialized properly, or overwritten by some unrelated piece of code, you might get some different junk when you connect things to, or disconnect things from the board. Or whenever some environmental factor changes.

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

No, it just manages to hide the problem by sheer luck. With a corrupt heap, all bets are off.

You are starting debugging from the wrong end. Did you check the value returned by malloc? Probably not.

If the address is invalid it usually means that your linker script is wrong.

Show us everything. The result of the malloc, the actual code and the linker script.

Related