carmmallocstm32keil

Troubleshooting malloc Usage and heap_size Configuration in STM32 Development


I'm currently working with ST's ARM-M4 chip to develop a program and have ported a networking library. During debugging, I've noticed that if I don't increase the heap_size in my .s file to 0x400, the program crashes. I've already replaced the system's malloc interface with my own dynamic memory allocation function mymalloc. However, when I examine the .map linker file, I still see references to the malloc function in some file, yet I can't find the actual line of code where malloc is being called in the .map file.

My Questions: In the MDK environment for ST, are there better methods to determine if the system's malloc function is being called? For instance, can breakpoints be set online?

Does the heap_size in the .s startup file on STM32 serve purposes beyond just dynamic memory allocation functions like malloc?

Besides dynamic memory allocation functions related to malloc, what other system library functions might use malloc?

My Attempts: At the top of my header file, I used #define malloc mymalloc to replace the system's malloc. I replaced the system's malloc with my own implementation using the library's malloc interface.


Solution

  • In the MDK environment for ST, are there better methods to determine if the system's malloc function is being called? For instance, can breakpoints be set online?

    This is a long answer; see below.

    Does the heap_size in the .s startup file on STM32 serve purposes beyond just dynamic memory allocation functions like malloc?

    The stack will grow into the heap. If the heap is not used, it extends the stack. But if you don't define the heap, then that stack is just bigger. It is hard to answer your question as some systems might use the heap for various things. Generally, no, not normally.

    Besides dynamic memory allocation functions related to malloc, what other system library functions might use malloc?

    You can see the list here. Ultimately, it is all just sbrk as per my original answer below.


    Newlib documents sbrk use. I use git grep -l sbrk inside a git repo of newlib for a list below. There is a large comment sections in the source and it looks like a doc format. For example, fread.c has this,

    PORTABILITY
    ANSI C requires <<fread>>.
    
    <<fread_unlocked>> is a BSD extension also provided by GNU libc.
    
    Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
    <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
    

    This is a link to the formatted information.

    List of sbrk files.

    newlib/libc/posix/popen.c
    newlib/libc/reent/sbrkr.c
    newlib/libc/signal/psignal.c
    newlib/libc/stdio/diprintf.c
    newlib/libc/stdio/dprintf.c
    newlib/libc/stdio/fclose.c
    newlib/libc/stdio/fcloseall.c
    newlib/libc/stdio/fgetc.c
    newlib/libc/stdio/fgets.c
    newlib/libc/stdio/fmemopen.c
    newlib/libc/stdio/fopen.c
    newlib/libc/stdio/fopencookie.c
    newlib/libc/stdio/fputc.c
    newlib/libc/stdio/fputs.c
    newlib/libc/stdio/fread.c
    newlib/libc/stdio/freopen.c
    newlib/libc/stdio/fseek.c
    newlib/libc/stdio/fseeko.c
    newlib/libc/stdio/fsetpos.c
    newlib/libc/stdio/funopen.c
    newlib/libc/stdio/fwrite.c
    newlib/libc/stdio/getc.c
    newlib/libc/stdio/getc_u.c
    newlib/libc/stdio/getchar.c
    newlib/libc/stdio/getchar_u.c
    newlib/libc/stdio/gets.c
    newlib/libc/stdio/nano-vfprintf.c
    newlib/libc/stdio/open_memstream.c
    newlib/libc/stdio/perror.c
    newlib/libc/stdio/putc.c
    newlib/libc/stdio/putc_u.c
    newlib/libc/stdio/putchar.c
    newlib/libc/stdio/putchar_u.c
    newlib/libc/stdio/puts.c
    newlib/libc/stdio/setbuf.c
    newlib/libc/stdio/setbuffer.c
    newlib/libc/stdio/setlinebuf.c
    newlib/libc/stdio/setvbuf.c
    newlib/libc/stdio/siprintf.c
    newlib/libc/stdio/siscanf.c
    newlib/libc/stdio/sprintf.c
    newlib/libc/stdio/sscanf.c
    newlib/libc/posix/popen.c
    newlib/libc/reent/Makefile.am
    newlib/libc/reent/Makefile.in
    newlib/libc/reent/reent.tex
    newlib/libc/reent/sbrkr.c
    newlib/libc/signal/psignal.c
    newlib/libc/stdio/diprintf.c
    newlib/libc/stdio/dprintf.c
    newlib/libc/stdio/fclose.c
    newlib/libc/stdio/fcloseall.c
    newlib/libc/stdio/fgetc.c
    newlib/libc/stdio/fgets.c
    newlib/libc/stdio/fmemopen.c
    newlib/libc/stdio/fopen.c
    newlib/libc/stdio/fopencookie.c
    newlib/libc/stdio/fputc.c
    newlib/libc/stdio/fputs.c
    newlib/libc/stdio/fread.c
    newlib/libc/stdio/freopen.c
    newlib/libc/stdio/fseek.c
    newlib/libc/stdio/fseeko.c
    newlib/libc/stdio/fsetpos.c
    newlib/libc/stdio/funopen.c
    newlib/libc/stdio/fwrite.c
    newlib/libc/stdio/getc.c
    newlib/libc/stdio/getc_u.c
    newlib/libc/stdio/getchar.c
    newlib/libc/stdio/getchar_u.c
    newlib/libc/stdio/gets.c
    newlib/libc/stdio/nano-vfprintf.c
    newlib/libc/stdio/open_memstream.c
    newlib/libc/stdio/perror.c
    newlib/libc/stdio/putc.c
    newlib/libc/stdio/putc_u.c
    newlib/libc/stdio/putchar.c
    newlib/libc/stdio/putchar_u.c
    newlib/libc/stdio/puts.c
    newlib/libc/stdio/setbuf.c
    newlib/libc/stdio/setbuffer.c
    newlib/libc/stdio/setlinebuf.c
    newlib/libc/stdio/setvbuf.c
    newlib/libc/stdio/siprintf.c
    newlib/libc/stdio/siscanf.c
    newlib/libc/stdio/sprintf.c
    newlib/libc/stdio/sscanf.c
    

    It is quite possible one of your networking functions use these. Use of sbrk does not imply a malloc call, but this is the underlying use of heap Using an idea of a breakpoint on malloc, a breakpoint on sbrk is probably more poignant.

    All STM tools seem to just bundle newlib, it will be baked into the compiler (arm-none-eabi-gcc, which is a gcc version with a newlib version of libc).

    From the same document/link on sbrk().

    sbrk ¶ Increase program data space. As malloc and related functions depend on this, it is useful to have a working implementation. The following suffices for a standalone system; it exploits the symbol _end defined in the GNU linker script.

    caddr_t sbrk(int incr) {
      extern char _end;     /* Defined by the linker */
      static char *heap_end;
      char *prev_heap_end;
     
      if (heap_end == 0) {
        heap_end = &_end;
      }
      prev_heap_end = heap_end;
      if (heap_end + incr > stack_ptr) {
        write (1, "Heap and stack collision\n", 25);
        abort ();
      }
    
      heap_end += incr;
      return (caddr_t) prev_heap_end;
    }
    

    Does the heap_size in the .s startup file on STM32 serve purposes beyond just dynamic memory allocation functions like malloc?

    The line extern char _end; is the one related to the linker file and as the sbrk and 'allocation function' sections detail, this creates the 'heap' which is some concepts that most libc implementation stick to.

    If you wrote a custom OS, you can redefine sbrk and for instance, assign MPU/MMU section as more memory is grabbed for a process. The implementation above is for bare metal or single main line (well, maybe as others noted, you generally may wish to avoid this completely).

    My Attempts: At the top of my header file, I used #define malloc mymalloc to replace the system's malloc. I replaced the system's malloc with my own implementation using the library's malloc interface.

    It is better to replace the sbrk() inside of sysmem.c (or syscall.c)... depending on the specific STM32 tools you are using. As an alternative of using a define to try and wrap malloc().

    Reference: Newlib always fails