gcc-arm-none-eabi-4.7-2013q1 -> Problems with malloc

Asked by Robert Chudalla

 Test ! (used CPU stm32f407)
void *p;

p = malloc(50);

if (!p)
{
 error = ERRCODE_OUTOFMEMORY;
}
else
{
 error = ERRCODE_SUCCESS;
}

// Pointer p always = 0 with gcc-arm-none-eabi-4.7-2013q1
// Pointer p = 0x200037b8 (HEAP RAM Area) with gcc-arm-none-eabi-4.7-2012q4, it's O.k.

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Robert Chudalla
Solved:
Last query:
Last reply:
Revision history for this message
chengbin (can-finner) said :
#1

Hi,
Could you please provide more information like:
1. which library do you link with your program, Newlib or Newlib-nano?
2. Is there enough heap memory when trying to allocate?

You can do below experiments to identify the root cause:
1. Print the sp register just before calling malloc, to see whether there is enough heap memory.
2. If you linked with Newlib, please try the program with Newlib-nano. Generally Newlib requires about 1KB+ memory even the program asks for only 50bytes.

One possible reason is program built with gcc-arm-none-eabi-4.7-2013q1 uses more memory, causing the allocation failed.

Revision history for this message
Joey Ye (jinyun-ye) said :
#2

Robert,

From the limited description you provided, I guess it is related to https://answers.launchpad.net/gcc-arm-embedded/+question/218972

4.7 2012q4 doesn't check heap overflow. 2013q1 fixed it.

Thanks - Joey

Revision history for this message
Robert Chudalla (robert-chudalla) said :
#3

Hello together,

sorry for my late answer.

Now I have time to check my heap problem again and
the problem is still present for the following both GCC versions.

gcc-arm-none-eabi-4.7-2013q1
Newlib-nano: newlib branch optimized for code size

gcc-arm-none-eabi-4.7-2013q2
Newlib-nano: newlib branch optimized for code size

Details for my test.

1.
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x1000; /* required amount of heap set to 4096 Byte */
_Min_Stack_Size = 0x1000; /* required amount of stack set to 4096 Byte*/

2. We using the real time operating system (rtos) from SEGGER (embOS_CortexM_GNU_Src_V386i_100747_nO9bfExU_121001)
     LIB: libosT7VL_D.a

Heap check -> _sbrk function.

/*********************************************************************
*
* _sbrk()
*
* Increase program data space. As malloc and related functions depend on this,
* it is required to have a working implementation.
* The following suffices for a standalone system; it exploits the symbol _end automatically defined by the GNU linker.
*/
caddr_t _sbrk(int incr) {
  extern char __heap_start__; /* Has to be defined in the linker file. */
  extern char __heap_end__;
  static char * heap_end;
  char * prev_heap_end;

  if (heap_end == NULL) {
    heap_end = & __heap_start__;
  }
  prev_heap_end = heap_end;

  if (heap_end + incr > &__heap_end__) {
      /* Some of the libstdc++-v3 tests rely upon detecting
        out of memory errors, so do not abort here. */
      errno = ENOMEM;
      return (caddr_t) -1;
  }

  heap_end += incr;
  return (caddr_t) prev_heap_end;
}

3. Heap test source code: -> get no Heap RAM buffer !!

        data1 = 0;
 data2 = 0;

 // get heap RAM
 data1 = OS_malloc(100); // rtos function
 if (!data1)
 {
  error = ERRCODE_OUTOFMEMORY;
  memset(&info, 0x00, sizeof(info));
  info = mallinfo();
 }
 else
 {
  memset(&info, 0x00, sizeof(info));
  info = mallinfo();
  count++;
  OS_free(data1); // rtos function
 }

4. RTOS functions

/**********************************************************************
*
* OS_malloc
*
***********************************************************************
Purpose:
*/

void* OS_malloc(unsigned int Size) {
  void *p;

  OS_TRACE_START(); /* Calls OS_EnterRegion(), if trace is enabled */
  if (OS_IsRunning()) {
    //
 // Locking is required when called from tasks
 //
    #if OS_TRACE == 0
      OS_EnterRegion();
    #endif
    if (!IsInited) {
      OS_CREATERSEMA(&RSema);
      IsInited = 1;
    }
    #if OS_TRACE == 0
      OS_LeaveRegion();
    #endif
    OS_Use(&RSema);
  }

  p = malloc(Size);

  if (OS_IsRunning()) {
    //
 // Locking is required when called from tasks
 //
    OS_Unuse(&RSema);
  }
  OS_TRACE_DATA_PTR(OS_TRACE_ID_MALLOC, Size, p);
  OS_TRACE_END(); /* Calls OS_LeaveRegion(), if trace is enabled */
  return p;
}

/**********************************************************************
*
* OS_free
*
***********************************************************************
Purpose:
*/

void OS_free (void* pMemBlock) {
  OS_TRACE_START(); /* Calls OS_EnterRegion(), if trace is enabled */
  if (OS_IsRunning()) {
    //
 // Locking is required when called from tasks
 //
    OS_Use(&RSema);
  }

  free(pMemBlock);

  if (OS_IsRunning()) {
    //
 // Locking is required when called from tasks
 //
    OS_Unuse(&RSema);
  }
  OS_TRACE_PTR(OS_TRACE_ID_FREE, pMemBlock);
  OS_TRACE_END(); /* Calls OS_LeaveRegion(), if trace is enabled */
}

Thanks Robert

Revision history for this message
chengbin (can-finner) said :
#4

Hi,
Thanks for your information. Could you please do the experiment I mentioned in the first reply? that would be : print sp register and heap_end before/after the failing malloc (maybe for both 2013q1 and 2012q4 releases).
I think it's possible that 2013q1/q2 releases consume more memory than 2012q4 release. If this is true, the printed sp/heap_end would show that we are running out of memory for 2013q1 release and almost running out of memory for 2012q4 release.

Thanks.

Revision history for this message
Robert Chudalla (robert-chudalla) said :
#5

Info heap, stack area for generated *map file (CPU STM32F405 ZGT6)

._user_heap_stack
                0x200070f0 0x2000 load address 0x08039130
                0x200070f0 . = ALIGN (0x8)
                0x200070f0 __heap_start__ = .
                0x200080f0 . = (. + _Min_Heap_Size)
 *fill* 0x200070f0 0x1000 00
                0x200080f0 __heap_end__ = .
                0x200080f0 . = ALIGN (0x8)
                0x200080f0 __stack_start__ = .
                0x200090f0 . = (. + _Min_Stack_Size)
 *fill* 0x200080f0 0x1000 00
                0x200090f0 __stack_end__ = .
                0x200090f0 _estack = .
                0x200090f0 . = ALIGN (0x8)

Read sp before call first time:

data1 = OS_malloc(100); // rtos function

gcc-arm-none-eabi-4.7-2013q2

Main Stack Pointer
MSP = 0x200090c8

Process Stack Pointer
PSP = 0x20001528

SP = 0x20001528

heap end = 0x200080f0

gcc-arm-none-eabi-4.7-2012q4

Main Stack Pointer
MSP = 0x200090c8

Process Stack Pointer
PSP = 0x20001528

SP = 0x20001528

heap end = 0x200080f0

Revision history for this message
Robert Chudalla (robert-chudalla) said :
#6

Hello ,

I solved my problem.

-> I forget to use the special defined _sbrk() function for using the rtos.

Now the heap overflow check works.

Thanks a lot
Bye
Robert