heap_5 allocating outside of allowed range

avnimaor wrote on Sunday, April 26, 2015:

I’m using STM32F4 which has 192+64 KB of RAM. To use the 64KB I’m using heap_5.

Currently the heap is initialized for the 64KB plus the upper 64KB of the 192KB.

From the linker script file:

define symbol __region_HEAP_1_start__ = 0x10000000;
define symbol __region_HEAP_1_end__   = 0x1000FFFF;
define symbol __region_HEAP_2_start__ = 0x20010000;
define symbol __region_HEAP_2_end__   = 0x2002FFFF;

Heap initialization code:

HeapRegion_t xHeapRegions[] =
{
    {   ( uint8_t * ) 0, 0},
    {   ( uint8_t * ) 0, 0},
    {   NULL, 0}//<< Terminates the array.
};

void fillHeapRegions()
{
    xHeapRegions[0].pucStartAddress = &__region_HEAP_1_start__;
    xHeapRegions[0].xSizeInBytes = &__region_HEAP_1_end__-&__region_HEAP_1_start__;
    xHeapRegions[1].pucStartAddress = &__region_HEAP_2_start__;
    xHeapRegions[1].xSizeInBytes = &__region_HEAP_2_end__-&__region_HEAP_2_start__;
}

I’m calling fillHeapRegions before calling vPortDefineHeapRegions(xHeapRegions) in main.

My application works fine with this configuration.

The problem I’m witnessing is if I reduce the size of the memory region allocated to the heap:

define symbol __region_HEAP_1_start__ = 0x10000000;
define symbol __region_HEAP_1_end__   = 0x1000FFFF;
define symbol __region_HEAP_2_start__ = 0x20012000;
define symbol __region_HEAP_2_end__   = 0x2002FFFF;

I’m getting sporadic application crashes. When I investigated those crashes I saw a pointer to 0x20030000. Naturally this would cause a hard fault as this address is outside allowed address space.

Any idea?

Thanks,

Maor

heinbali01 wrote on Sunday, April 26, 2015:

Hi Maor,

I’m getting sporadic application crashes

I would wonder if all memories given to the HEAP is not used by your program or by some stack?

You can also set the sizes more dynamically. If your linker file contains symbols like:

_ebss = . ;
_edata = . ;

you can obtain the addresses of these variable in your C code:

extern void _edata;
extern void _ebss;

and convert them to real addresses:

uint32_t end_data = ( uint32_t ) &_edata;
uint32_t end_bss = ( uint32_t ) &_ebss;

A small remark about your code:

xSizeInBytes = &__region_HEAP_1_end__ - &__region_HEAP_1_start__;

Shouldn’t it be: size = end - start + 1 ?

Regards.

avnimaor wrote on Sunday, April 26, 2015:

First, the memory is divided to three segments, one for the statically allocated memories and the other two for the segmented heap.

As an architectural limit, I can’t move the static memories to the lower segment as hardware peripherals don’t work there.

I started the allocation by giving 64K to the static memories, and 64+64K to the heap. I got a linking error when I needed more statically allocated memory and I resized the segments accordingly. At this point I started getting the crashes.

As for the size in bytes, it really doesn’t matter - I shouldn’t be getting allocation addresses outside of the allowed range.

davedoors wrote on Monday, April 27, 2015:

define symbol region_HEAP_1_start = 0x10000000;
xHeapRegions[0].pucStartAddress = &region_HEAP_1_start;

What compiler is that? Can you check it is doing what you think by looking at the xHeapRegions structure in the debugger? It looks like it is taking the address of region_HEAP_1_start not its value. I would do this

#define region_HEAP_1_start 0x10000000
xHeapRegions[0].pucStartAddress = (unsigned char*) region_HEAP_1_start;

The other thing to do would put some code in heap_5 so you can break when the memory returned is out of bounds:

if( returned address < min address OR returned address > max address )
{
asm volatile(“NOP”); // Line for break point
}

when the break point is hit look at the variables in heap_5 to see why it was out of bounds.

If you define configASSERT() it might trap an invalid vPortFree call, which might be the problem.

avnimaor wrote on Wednesday, May 27, 2015:

Still getting these issues.

The compiler is IAR 7.4. The heap regions are initialized correctly.

I even reduced the upper limit to account for heap bugs…

In the last crash I got I had a hard fault within memcpy. When I the registers I got r0 = 0x10010001. This is outside the range of the heap which the upper limit is 0x1000FF00.

This behavior is observed randomly after our PC connects to the board and configures the behavior of the application. During this phase tens of small messages are sent to the application, and many memory allocs and deallocs are called.

Once the first phase is complete the application is stable, but the instability of the first phase is a critical issue for us.

BTW, I switched to heap_5 from heap_4, and never observed these faults before, which leads me to the conclusion that this is specific to heap_5.

heinbali01 wrote on Wednesday, May 27, 2015:

My reaction would be:

Make absolutely sure that your application never writes to unallocated memory. If you malloc N bytes, do not use N+1 bytes.

If you are not sure if memories get overwritten, as a test, malloc() more than you need and see if the extra bytes are still untouched before calling ‘vPortFree()’.

r0 = 0x10010001 ? Beside being outside the memory, it is an unaligned address.
Sometimes I saw memcpy() crashing because it was replaced (optimised) by ‘inline’ instructions performing 32-bit operations on a non-aligned address. I’m not sure if IAR would do the same.
In GCC this problem can be avoided by using the compiler flag ‘-fno-builtin-memcpy’. The memcpy() function is always safe to call, also for unaligned addresses.

Regards.

rtel wrote on Wednesday, May 27, 2015:

That is a good observation, although heap_4 and heap_5 are almost
identical when it comes to allocation and free algorithms. The main
different between the two is their initial state - before anything has
been allocated.

Do you ever call these functions from an interrupt?

Regards.

avnimaor wrote on Wednesday, May 27, 2015:

r0=0x10010001 is probably a temporary address that was used by memcpy until it crashed. I think it’s safe to assume that the allocation routine did not return this address by itself.

I did saw malloc returning address 0x10010000 and 0x20020000 (which is the other segment top address) several times. That’s why I lowered the upper limits…

As for use of the mallocs, I’m 99.999% sure that I don’t malloc in ISR. I’ll have to review the code, but I’m aware this is a huge no-no, and try to statically allocate/preallocate memories used in ISR.

Secondly my application is 95% C++. I overloaded all required prototypes of the “new” operator to use pvPortMalloc and vPortFree. I always access pointers to classes and I never deal directly with pointers to allocated buffer, therefore I find it hard to believe that I overwrite the end of the allocated buffers.

Again, I never observed these memory overwrites/hard faults/whatever when I used heap_4.