When does malloc return NULL in a bare-metal environment?

蓝咒 提交于 2019-12-09 18:40:59

问题


There is a c memory model as following :

      +--------+   Last Address of RAM
      | Stack  |
      |   |    |
      |   v    |
      +--------+
RAM   |        |
      |        |
      +--------+
      |   ^    |
      |   |    |
      | Heap   |
      +--------+
      |   ZI   |
      +--------+
      |   RW   |  
      +========+  First Address of RAM

The stack and heap space increase in opposite directions. They would be overlapped with each other in the middle. So my questions are:

  • In a bare-metal environment, when does malloc return NULL?
  • In a bare-metal environment, how to prevent stack from overlapping with heap?

回答1:


@WikiWang is correct if you are using a static, compile-time memory layout (edit although you have to tell your malloc implementation somehow where the end of the heap is).

If not, and assuming you mean bare-metal, it depends on the C library implementation in your board-support package. The library must provide some implementation of brk(2) or a function having a similar effect. malloc works within the area of memory set by brk or sbrk. For example, see the malloc source calling macro MORECORE, which is by default sbrk. Your C library will have to use something other than a kernel call for that :) .




回答2:


Size of stack is determinded at compile time.

      +--------+   Last Address of RAM
      | Stack  |
      |   |    |
      |   v    |
      +--------+
RAM   |        |
      +--------+   Stack Limit
      |        |
      +--------+
      |   ^    |
      |   |    |
      | Heap   |
      +--------+
      |   ZI   |
      +--------+
      |   RW   |  
      +========+  First Address of RAM

malloc return null if there is not enough space for the requested heap.

And its your duty to to prevent stack overflow!




回答3:


when does malloc return NULL?

It may depend on C compiler and library implementation. For example, my malloc implementation calls sbrk, which is a system call in Linux environment. As we have no Linux on the MCU, I provided my own implementation of sbrk like this:

// Global variables.
extern unsigned int _heap;
extern unsigned int _eheap;
static caddr_t heap = NULL;

caddr_t _sbrk(int incr)
{
  caddr_t prevHeap;
  caddr_t nextHeap;

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

  prevHeap = heap;

  // Always return data aligned on a 8 byte boundary
  nextHeap = (caddr_t) (((unsigned int) (heap + incr) + 7) & ~7);
  if (nextHeap >= (caddr_t) & _eheap) {
    errno = ENOMEM;
    return ((void*)-1); // error - no more memory
  } else {
    heap = nextHeap;
    return (caddr_t) prevHeap;
  }
}

and _eheap is defined in the linker script:

PROVIDE ( _eheap = ALIGN(ORIGIN(ram) + LENGTH(ram) - 8 ,8) );

Having this, malloc in my program will return error only when it hits the end of the memory. Stack top address is not recognized, thus I cannot diagnose possible stack corruption by checking malloc return value.

how to prevent stack from overlapping with heap?

You may define your own limit for sbrk to return error, which will prevent malloc from invading stack memory.




回答4:


1) bare metal you probably dont want to use malloc in the first place

2) bare metal you own that memory and manage it so you are the only one that can answer the question.

3) even on not-bare-metal (windows, linux, etc) stack hitting the heap or running into the code space is not something you normally get protections from, you need to either tell the compiler, if it supports it, to add a ton more code, or you just design your software right to not collide.

What is your memory allocation scheme, what does your code do, how if at all have you told this code what space it can allocate from. If the compiler supports it at all you may need to tell the compiler the space or runtime indicate where the top of heap is currently. Or maybe the compiler relies on that space being filled with a pattern and it checks for the pattern before allocating, which means in bare metal for a case like that you would need to fill that memory with that pattern. First and foremost you need to find out if and how the compilers output works with respect to preventing the stack colliding with data or program space.

Normally you know by your system/software design how deep your stack will go worst case, and from that how much memory you have left. As you do your design and then implementation you verify the maximum stack depth, how much ram you ended up needing and making sure you have not oversubscribed the ram you have available for that processor in that system.

Bare metal there is no reason to expect the compiler nor libraries nor other tools to do this work for you.




回答5:


malloc will return NULL when the allocation fails. Usually this is due to lack of memory. In a free-running model, where heap and stack don't have limits, it would always give you memory (even if that meant colliding with the stack).

Fortunately, that is never done. Usually the heap and the stack have fixed maximum sizes, so checks are easier. For example, if the library malloc calls your sbrk (typical situation), you could write sbrk so that it refuses to extend the heap past the stack limit. This avoids the heap from colliding into the stack.

The other way around (stack collides into heap) is trickier. First off, there isn't much you can do to recover from a stack overflow, so the strategy here would be to produce useful debug info and halt the system to avoid working on corrupted memory. Technically, the compiler could add checks for every stack allocation, but that would noticeably slow down the code (I don't even know if any compiler supports it - probably yes, with some instrumentation). If your MCU has a Memory Protection Unit (MPU), you could configure a small unaccessible zone above the stack limit, so that stack overflows will generate an MPU fault. This technique is often called guard page (much like guard bytes with a memory breakpoint, if you want). For this to work, however, exceptions need to use a different stack (otherwise you're in the same boat). Note that stack canaries don't protect against stack-heap collision.

That being said, in bare metal you are the one designing the memory layout, and you can set it up however you want depending on your needs. malloc is generally frowned upon because it's non-deterministic. Also, you should profile your stack usage and know your maximum stack depth in order to properly size the stack.



来源:https://stackoverflow.com/questions/39113658/when-does-malloc-return-null-in-a-bare-metal-environment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!