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 returns NULL

Setup

Keil: uVision 5.17.0.0
ARM: LPC1768
A standard project with some UARTS and I2C
"Use memory Layout form target" is checked (using the standard scatter file)
"Use MicroLIB" is not checked

from startup_LPC17xx.s
Heap_Size EQU 0x00002000

AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit

Problem
Any call to malloc returns NULL, that is, the system can not allocate memory.

Why does not the mallco work, is my only options to
1) Use microLIB
2) Implement _init_alloc() and __rt_heap_extend() on my own

?

Regards Stefan

Parents
  • Or if you want to go the path you are, you can implement the __user_initial_stackheap function yourself.

    ; User Initial Stack & Heap
    
                    IF      :DEF:__MICROLIB
    
                    EXPORT  __initial_sp
                    EXPORT  __heap_base
                    EXPORT  __heap_limit
    
                    ELSE
    
                    IMPORT  __use_two_region_memory
                    EXPORT  __user_initial_stackheap
    __user_initial_stackheap
    
                    LDR     R0, =  Heap_Mem
                    LDR     R1, =(Stack_Mem + Stack_Size)
                    LDR     R2, = (Heap_Mem +  Heap_Size)
                    LDR     R3, = Stack_Mem
                    BX      LR
    
    

Reply
  • Or if you want to go the path you are, you can implement the __user_initial_stackheap function yourself.

    ; User Initial Stack & Heap
    
                    IF      :DEF:__MICROLIB
    
                    EXPORT  __initial_sp
                    EXPORT  __heap_base
                    EXPORT  __heap_limit
    
                    ELSE
    
                    IMPORT  __use_two_region_memory
                    EXPORT  __user_initial_stackheap
    __user_initial_stackheap
    
                    LDR     R0, =  Heap_Mem
                    LDR     R1, =(Stack_Mem + Stack_Size)
                    LDR     R2, = (Heap_Mem +  Heap_Size)
                    LDR     R3, = Stack_Mem
                    BX      LR
    
    

Children
  • To Per Westermark

    Accoring the searching I did before I made post it said that a main like this, "int main(int argc, char **argv)" require a initiation of the heap. That is, the function __user_initial_stackheap must/will be called unlike if "use microlib" is checked, then the main must look like this "void main(void)"


    To Westonsupermare Pier

    I have changed it, but it wont call the __user_initial_stackheap before calling main


    To Robert McNamara

    ARM_LIB_HEAP: Yes, i have tested it, it did not make any difference, it still wont call __user_initial_stackheap before main(...)

    __user_initial_stackheap is included, I used "new project" option the keil and it automatically produced that code, but it is not calle



    To All
    Becosue "new project" produced startup_LPC17xx.s, with the stack, heap reserved and __user_initial_stackheap created (without changing the scatter file) I assumed everything should be working, but it seems not to be.



    Regards Stefan

  • No, it is pure C, one single main function

    I even recreated an empty project ("use microlib" unchecked) to test it again.
    When i step into the malloc function i can see that the malloc function consider the heap to be full and it wont call the __user_initial_stackheap

    In the map file the following exists so something is going on

    __user_initial_stackheap 0x000002cd Thumb Code 0 startup_lpc17xx.o(.text)
    __use_two_region_memory 0x000002f1 Thumb Code 2 heapauxi.o(.text)
    __rt_heap_escrow 0x000002f3 Thumb Code 2 heapauxi.o(.text)
    __rt_heap_expand 0x000002f5 Thumb Code 2 heapauxi.o(.text)
    __use_no_heap 0x000002f7 Thumb Code 2 hguard.o(.text)


    Is it possibly to get the source code to the c libraries that the linker automatically links in so i can compare it to the executed assembler instructions in "malloc" ?

    and that coudl help me to understand why it is not calling the __user_initial_stackheap


    Regards

  • What size is your heap?

    How much are you trying to allocate in your main?

    If you make the heap 0 in size, does it crash before main?

    If you make the heap larger does it eventually work?

    When you set your breakpoint in __user_initial_stackheap, make sure you also right click and then left click "show disassembly at ###" Then see if it stops in your __user_inital_stackheap.


  • startup_LPC17xx.s

    Stack_Size      EQU     0x00000800
    
                    AREA    STACK, NOINIT, READWRITE, ALIGN=3
    Stack_Mem       SPACE   Stack_Size
    __initial_sp
    
    
    ; <h> Heap Configuration
    ;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
    ; </h>
    
    Heap_Size       EQU     0x00000800
    
                    AREA    HEAP, NOINIT, READWRITE, ALIGN=3
    __heap_base
    Heap_Mem        SPACE   Heap_Size
    __heap_limit
    

    Scatter file

    
    LR_IROM1 0x00000000 0x00080000  {    ; load region size_region
      ER_IROM1 0x00000000 0x00080000  {  ; load address = execution address
        *.o (RESET, +First)
        *(InRoot$$Sections)
        .ANY (+RO)
      }
    
      RW_IRAM_STACK 0x10000000 0x2000  {  ; RW data
        .ANY (STACK)
      }
    
      LO_ARM_TEST 0x10002000 UNINIT 0x20 {  ; RW data
        .ANY (__LO_ARM_TEST_RAM_AREA)
      }
    
      RW_IRAM1 0x10002020 0x3FE0  {  ; RW data
        .ANY (+RW +ZI)
      }
    
      RW_IRAM_HEAP 0x10006000 0x2000 {  ; RW data
        .ANY (HEAP)
      }
    }
    

    yes, i have the assembler view up as awell, i have a break point at __user_inital_stackheap and the main function


    The execution do

    
                    LDR     R0, =SystemInit
                    BLX     R0
                    LDR     R0, =__main
                    BX      R0
    

    And then it will hit the main function without hitting __user_inital_stackheap.

    If i do
    v = malloc(0x10);

    it will return NULL
    but if i have called _init_alloc((uintptr_t)&__heap_base, (uintptr_t)&__heap_limit); before the malloc it will not return a NULL pointer and the pointer is in "right area"

    "use microlib" is unchecked, my main function look like this

    int main(int argc, char **argv)
    


    I have not tested to set "If you make the heap 0 in size, does it crash before main?"



    Regards Stefan

  • heap test of 0?

    Try removing __user_initialize_stackheap and the EXPORT of it from the startup file. Do you get a link error?

  • Test1

    Heap_Size       EQU     0x00000000
    
    Result:
    No compilation error
    It hangs inside _init_alloc call in the main function
    



    Test2

    Heap_Size       EQU     0x00000000
    ;                EXPORT  __user_initial_stackheap
    //  _init_alloc((uintptr_t)&__heap_base, (uintptr_t)&__heap_limit);
    Result:
    No compilation error
    It never reach the main() function
    



    Test3:

    Heap_Size       EQU     0x00000800
    ;                EXPORT  __user_initial_stackheap
    //  _init_alloc((uintptr_t)&__heap_base, (uintptr_t)&__heap_limit);
    Result:
    No compilation error
    It reach the main() function
    and malloc returns a valid pointer (that is, it points into the right area)
    

    wtf, why would it work corretly with "standard" code comment out?

    Regards

  • "That really seems like the way you would allocate a heap in previous versions, but not in any recent."

    So maybe you got two separate functions that tries to initialize the heap.

  • I am using Keil: uVision 5.17.0.0

    But ARM says that __user_initial_stackheap is a legacy thingy
    infocenter.arm.com/.../index.jsp
    and the, nowdays, the proper function should be __user_setup_stackheap()

    I gues the Keil runtime library get messaed up if it see the __user_initial_stackheap() and does not initilize heap (internally) nor does it call __user_initial_stackheap.

    It seems that the only way is to hide __user_initial_stackheap from Keil so it does not see it and assume it have to initilize the heap itself.
    Note, if __user_initial_stackheap is comment out, it is neccessary as well to do the following at the begining of startup_LPC17xx.s

                    EXPORT  __heap_base
                    EXPORT  __heap_limit
    

    Regards Stefan

  • 1) Stop making any calls to _init_alloc.

    2) You should be getting a link error on TEST2, no compile error. See #4 below. This would only seem to be if you exported __heap_limit, __heap_base and __initial_sp. If you export these, it will compile and link fine using both microlib and standardlib, but will not actually work in standardlib mode. Did you somehow change the standard code in a way that these variables were exported when not using the microlib? You may notice in the map file that sys_stackheap_outer.o references a __user_inital_stackheap that resides in sys_stackheap_outer.o when these are exported. If you do not export these variables, it will reference the __user_initial_stackheap in YOUR startup.s file. This is why your __user_initial_stackheap is not being called. i.e. You are not using the "standard" code at all, you have modified it to not work and then complained about it not working.

    3) Look at your map file

    USING:__user_setup_stackheap,
    
    your map file should show __rtentry4.o referencing __user_setup_stackheap in your startup.s file.  There is no reference to __user_initial_stackheap.
    
    USING: __user_initial_stackheap
    
    your mapfile should show sys_stackheap_outer.o referenceing __user_initial_stackheap in your startup.s file.  You will also see __user_setup_stackheap referenceing sys_stackheap_outer.o
    

    4) I have never seen __heap_limit defined as a variable when not using the microlib. I think the "standard" startup code is very specific in NOT creating a __heap_limit or __heap_base variable when not using the microlib. Don't define this as a variable.

  • It works now as expected, it was all related to one of all of the added lines at the top of startup_LPC..

                    EXPORT  __initial_sp
                    EXPORT  __heap_base
                    EXPORT  __heap_limit
    


    If any of them, even if the program only have "EXPORT __initial_sp" (and not the other two) the heap dont get initalized. If none of them are exported then the runtime library will call __user_initial_stackheap as expected.


    It is neccessary to export a new/seperate variabel if the stack top is going to be used
    somewhere else, like this

                    EXPORT  __initial_stack_top
    
    
    Stack_Size      EQU     0x00000800
    
                    AREA    STACK, NOINIT, READWRITE, ALIGN=3
    Stack_Mem       SPACE   Stack_Size
    __initial_sp
    __initial_stack_top
    


    One interesting observation was that if the program had

                    EXPORT  __initial_sp
                    EXPORT  __heap_base
                    EXPORT  __heap_limit
    
    The map file will contain
    __rtentry4.o(.ARM.Collect$$rtentry$$00000004) refers to sys_stackheap_outer.o(.text) for __user_setup_stackheap
    sys_stackheap_outer.o(.text) refers to startup_lpc17xx.o(.text) for __user_initial_stackheap
    
    But they was never called
    



    Conclusive:
    Dont export any of __initial_sp, __heap_base or __heap_limit form the startup_XXXX.s