This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

malloc/calloc returns NULL despite there are still space on heap

I am working on an application that allocate data dynamically at initialization, and my malloc/calloc returns NULL a lot earlier than I expected.

Using a debug macro, I determined that:

  • The last memory successfully allocated is 8 bytes at 0x200021A8.
  • I allocated 238 bytes for my data. Counting in overheads, the total should be +- 320 bytes.

I checked the memory map file and the heap is 2048B. I should not run out of memory yet.

HEAP                                     0x20002058   Section     2048  arm_startup_nrf51.o(HEAP)

What is going on?

I am using a nRF51 Dongle without SoftDevice. But this code is intended to be brought over to nRF51 running S110 v8 and nRF52 running the most up-to-date SoftDevice. I am a little worried about whether working with a SoftDevice will limit me even further.

Here is the macro I used for debugging:

#define DEBUG_ALLOC_MACRO(POINTER, NUM_ELEMENTS, TYPE)            \
  do                                                              \
  {                                                               \
    POINTER = (TYPE*) calloc(NUM_ELEMENTS, sizeof(TYPE));         \
    if (POINTER != NULL)                                          \
    {                                                             \
      mem_counter +=                                              \
          ((NUM_ELEMENTS * sizeof(TYPE)));                        \
    }                                                             \
    printf("%s(%d) Allocated %d x %s(%d) = %d B at 0x%p - Total %d B\n",  \
        __FILE__,                                                 \
        __LINE__,                                                 \
        NUM_ELEMENTS,                                             \
        #TYPE,                                                    \
        sizeof(TYPE),                                             \
        (NUM_ELEMENTS * sizeof(TYPE)),                            \
        POINTER,                                                  \
        mem_counter                                               \
        );                                                        \
  }                                                               \
  while (0)

And here is the log it generated.

file1.c(17) Allocated 1 x struct1(36) = 36 B at 0x20002060 - Total 36 B
file2.c(87) Allocated 8 x struct2(12) = 96 B at 0x20002088 - Total 132 B
parse_util.c(126) Allocated 4 x int16_t(2) = 8 B at 0x200020f0 - Total 140 B
parse_util.c(126) Allocated 5 x int16_t(2) = 10 B at 0x20002100 - Total 150 B
parse_util.c(126) Allocated 5 x int16_t(2) = 10 B at 0x20002110 - Total 160 B
parse_util.c(126) Allocated 1 x int16_t(2) = 2 B at 0x20002120 - Total 162 B
file2.c(100) Allocated 4 x struct3(28) = 112 B at 0x20002128 - Total 274 B
parse_util.c(90) Allocated 1 x uint8_t(1) = 1 B at 0x200021a0 - Total 275 B
parse_util.c(90) Allocated 8 x uint8_t(1) = 8 B at 0x200021a8 - Total 283 B
parse_util.c(90) Allocated 8 x uint8_t(1) = 8 B at 0x00000000 - Total 283 B
  • well who's malloc()/calloc() are you using? You should be able to find the source or step into the assembly and see where it's taking the heap limits from (perhaps you have an incorrect label) or why else it's returning zero.

    malloc()/calloc() are library routines so the ones you're using depend on the library you're linking with.

  • @rols: I used <stdlib.h> for malloc() and calloc(). I checked arm_startup_nrf51.s and the heap size there is also 2048. Heap limits should be 2048B away from heap base which is 0x20002058.

                    IF :DEF: __HEAP_SIZE
    Heap_Size       EQU     __HEAP_SIZE
                    ELSE
    Heap_Size       EQU     2048
                    ENDIF
    
                    AREA    HEAP, NOINIT, READWRITE, ALIGN=3
    __heap_base
    Heap_Mem        SPACE   Heap_Size
    __heap_limit
    

    I will go into debug mode and check what you recommend asap.

  • <stdlib.h> is where the functions are defined but the implementation comes from the library you liked with, ie gcc, nanolib or (in my case) an implementation from Segger Embedded Studio.

  • I determined the problem but still I am interested in learning how to debug problems like this.

    I used Keil uVision with default compiler version 5. How would I be able to determine the implementation of calloc()/malloc()? I tried using the disassembly and it takes me entire morning to find out that the Heap_Limit is loaded via LDR r0,[pc,#24] ; @0x0000183C

  • Found the problem. I used memcpy with the incorrect size and probably overwrote the headers of allocated memory. It is a mistake.