I’ve upgraded a project with two heap regions from FreeRTOS kernel ‘V10.5.1’ to ‘V11.1.0’. Everything works fine except for the call to vPortGetHeapStats() which gives me a hardfault error (which it didn’t in the previous version).
I’ve tested to revert only ‘heap_5.c’ with the old one, and then it works again.
There is not much in the heap when I call vPortGetHeapStats() and the loop in the function works until it moves to the heap region in SDRAM. Then the address pointer of pxBlock->pxNextFreeBlock looks tampered. Instead of pointing inside the SDRAM @ 0xC1000000 it is way off, and the block size is not 256 kB. There is nothing allocated in the SDRAM yet as the SRAM heap is not full.
Hi @lundholm
As a starting point, you can enable heap overflow checking by setting configENABLE_HEAP_PROTECTOR to 1 in the FreeRTOSConfig.h . V11.1.0 introduced bounds checking and obfuscation to internal heap block pointers in heap_4.c and heap_5.c to help catch pointer corruptions.
Yes, I saw this new flag and tried both enabled and disabled. Same outcome unfortunately. I will check again that Valgrind does not catch any buffer overwrites in my unit tests tomorrow. But I don’t think so and with the previous version of ‘heap_5.c’ it does work.
/Martin
Are you adding the end marker { NULL, 0 } in the array passed to vPortDefineHeapRegions? If yes, can you try to help debug what is causing this corruption? It may be a bug in the heap code and if so, we would like to fix that.
The heap region array is ended with the end marker.
I did an experiment where I set the first heap region as size of 1 kB and the second as 256 kB. My app allocates ~50 kB at startup, so it forces the memory manager to use the second heap. Then the vPortGetHeapStats() works fine! So vPortGetHeapStats() only crashes when there is no allocation in the second heap. As the pvPortMalloc() and vPortFree() works fine, there ought to be a difference in how blocks are handled compared to in vPortGetHeapStats().
My initial thought was that it is due to the address of the second heap starting at 0xC1000000. Maybe a sign extension or something in heapPROTECT_BLOCK_POINTER(), but the code in vPortGetHeapStats() is not that complicated and I really can’t see any such thing. Also, it crashes when configENABLE_HEAP_PROTECTOR is disabled and then the macro does nothing. Maybe I need to run it in assembler code…
I will first check if I put two heaps in the lower RAM and see if I get the same problem.
If I put both heap regions as 2 x 128 kB adjacent blocks in the lower address RAM (0x30000000), then vPortGetHeapStats() works fine. So, I guess it’s either the distance between the heap regions or the heap region address of 0xC1000000 which causes the crash.
I’ll see if I can spot the cause with the debugger.
Btw, what did you mean with “latest main code”? I did clone the most recent FreeRTOS-Kernel yesterday and copied that ‘heap_5.c’ in to my project. The last change of the ‘heap_5.c’ is dated at 2024-11-13.
After debugging for a while, I’m pretty convinced it’s my own code which overwrites the end block of the first heap region. It’s adjacent to the _estack marker from the link script, which is used by the _sbrk() function. It’s probably fluke of “luck” that it works with the older ‘heap_5.c’. I’ll be back…
It was a flaw in the linker script which was inherited from STM Cube to put the CPU stack at the end of the SRAM. Well, I rewrote the _sbrk() to simply use malloc() (for sprintf’s) instead of the STM Cube generated area in the linker script, but it wasn’t really the culprit.
So after some rearrangement it now works fine with the latest ‘heap_5.c’ Not sure why it ever worked before, but I’m just happy to have found the actual reason for the problem.
I really appreciate your response! Thank you very much!