malloc fails to allocate from desired heap

Asked by devan lippman

I am using GNU ARM Embbedded (newlib) 4.9 20014q4 to create a Cortex-M4 application.

The application tests memory allocations as follows:
extern unsigned int start_of_heap;
extern unsigned int end_of_heap;
extern caddr_t heap;

void foo(uint8_t i)
{
 unsigned long blah = 0;
 unsigned long * halb;
 halb = malloc(sizeof(unsigned long));
 printf("blah(%08x) halb(%08x) heap(%08x)\n", &blah, halb, heap);

 if(i)
  foo(i - 1);

 free(halb);

}

int main(int argc, char ** argv)
{
 init_uart((void*)UART2_IPS_BASE_ADDR, 115200);

 printf("Heap test (%08x - %08x)\n", &start_of_heap, &end_of_heap);
 foo(10);
 return 0;
}

The following output is generated:
Heap test (20000230 - 20000a30)
blah(20006fb0) halb(00000410) heap(a767ddfd)
blah(20006f98) halb(00000420) heap(a767ddfd)
blah(20006f80) halb(00000430) heap(a767ddfd)
blah(20006f68) halb(00000440) heap(a767ddfd)
blah(20006f50) halb(00000450) heap(a767ddfd)
blah(20006f38) halb(00000000) heap(a767ddfd)
blah(20006f20) halb(00000000) heap(a767ddfd)
blah(20006f08) halb(00000000) heap(a767ddfd)
blah(20006ef0) halb(00000000) heap(a767ddfd)
blah(20006ed8) halb(00000000) heap(a767ddfd)
blah(20006ec0) halb(00000000) heap(a767ddfd)

There are a few items that concern me but right now I'm focused on the address returned by malloc (00000410+). This appears out of range for the linker defined memory.

From the end of linker SECTIONS:
 end = .;
 start_of_heap = .;
 . += 2048;
 end_of_heap = .;

_sbrk is implemented as follows:
extern unsigned int start_of_heap;
extern unsigned int end_of_heap;
caddr_t heap = NULL;

// low level bulk memory allocator - used by malloc
caddr_t _sbrk ( int increment ) {

    caddr_t prevHeap;
    caddr_t nextHeap;

    if (heap == NULL) {
        // first allocation
        heap = (caddr_t)&start_of_heap;
    }

    prevHeap = heap;

    // Always return data aligned on a 8 byte boundary
    nextHeap = (caddr_t)(((unsigned int)(heap + increment) + 7) & ~7);

    // get current stack pointer
    register caddr_t stackPtr asm ("sp");

    // Check enough space and there is no collision with stack coming the other way
    // if stack is above start of heap
    if ( ((nextHeap > stackPtr)) ||
         (nextHeap >= (caddr_t)&end_of_heap)) {
        return NULL; // error - no more memory
    } else {
        heap = nextHeap;
        return (caddr_t) prevHeap;
    }
}

Where did I misstep?

Thanks,
Devan

UPDATE:
On further inspection the heap variable never appears to equal NULL so it is never initialized. If I change the heap initialization as follows it starts with a correct value:
caddr_t heap = (caddr_t)&_start_of_heap;

Despite this the malloc still appears to be returning bogus values (00000410+) while _sbrk is returning addresses within the region defined by the linker variables.

Question information

Language:
English Edit question
Status:
Expired
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
devan lippman (dlippman) said :
#1

I have made the following changes to the linker script to use available memory:
MEMORY
{
    SRAM_L (rwx) : ORIGIN = 0x00000000, LENGTH = 32K
    SRAM_U (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}

SECTIONS
{
    .vectors :
    {
        *o(.vectors_)
    }>SRAM_L

    .text :
    {
        . = ALIGN (4);
        *(.text)
    }

    .data 0x20000000 : AT ( ADDR(.text) + SIZEOF ( .text ) )
    {
        . = ALIGN (4);
        _data = . ; *(.data); _edata = . ;
    }

    .bss 0x20000000 + SIZEOF ( .data ) : AT ( ADDR(.data) + SIZEOF ( .data ) )
    {
     . = ALIGN (4);
     _bss = . ; *(.bss); _ebss = . ;
    }

    . = ADDR(.bss) + SIZEOF ( .bss );

    . = ALIGN (4);
    . += 8;

    free_memory_start = .;
    _end_of_stack = .;
    end = .;
    _start_of_heap = .;
    . = 0x20007000;
    _start_of_stack = .;
    _end_of_heap = .;

}

I then updated the _sbrk as follows:
extern unsigned int _start_of_heap;
extern unsigned int _end_of_heap;
caddr_t heap = (caddr_t)&_start_of_heap;

#include "hardware/uart.h"

// low level bulk memory allocator - used by malloc
caddr_t _sbrk ( int increment ) {

    caddr_t prevHeap;
    caddr_t nextHeap;

    send_str("_sbrk(");
    send_hex((uint32_t)increment);
    send_str(")\n");

    prevHeap = heap;

    // Always return data aligned on a 8 byte boundary
    nextHeap = (caddr_t)(((unsigned int)(heap + increment) + 7) & ~7);

    // get current stack pointer
    register caddr_t stackPtr asm ("sp");

    send_str("\tstackPtr(");
    send_hex((uint32_t)stackPtr);
    send_str(")\n");
    send_str("\tprevHeap(");
    send_hex((uint32_t)prevHeap);
    send_str(")\n");

    // Check enough space and there is no collision with stack coming the other way
    // if stack is above start of heap
    if((nextHeap < stackPtr) && (nextHeap < (caddr_t)&_end_of_heap)) {
     heap = nextHeap;
  return (caddr_t) prevHeap;
    }
    send_str("*\n");
    return NULL; // error - no more memory
}

'heap' is now initialized to an expected value (where NULL was not initialized the variable) and some debugging was added.

The following output is produced:
_sbrk(EA7EAAA8)
        stackPtr(20006DF0)
        prevHeap(20000030)
_sbrk(00000528)
        stackPtr(20006DF0)
        prevHeap(0A7EAAD8)
Heap test (20000030 - 20007000)
_sbrk(EA7EB000)
        stackPtr(20006F80)
        prevHeap(0A7EB000)
*
blah(20006fe0) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006F68)
        prevHeap(0A7EB000)
*
blah(20006fc8) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006F50)
        prevHeap(0A7EB000)
*
blah(20006fb0) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006F38)
        prevHeap(0A7EB000)
*
blah(20006f98) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006F20)
        prevHeap(0A7EB000)
*
blah(20006f80) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006F08)
        prevHeap(0A7EB000)
*
blah(20006f68) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006EF0)
        prevHeap(0A7EB000)
*
blah(20006f50) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006ED8)
        prevHeap(0A7EB000)
*
blah(20006f38) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006EC0)
        prevHeap(0A7EB000)
*
blah(20006f20) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006EA8)
        prevHeap(0A7EB000)
*
blah(20006f08) halb(00000000) heap(0a7eb000)
_sbrk(EA7EB000)
        stackPtr(20006E90)
        prevHeap(0A7EB000)
*
blah(20006ef0) halb(00000000) heap(0a7eb000)

It looks like the very first call the sbrk gets us off to a bad start with a requested allocation length of EA7EAAA8. What is the purpose for this?

Revision history for this message
Launchpad Janitor (janitor) said :
#2

This question was expired because it remained in the 'Open' state without activity for the last 15 days.