Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
382 views
in Technique[技术] by (71.8m points)

c - malloc behaviour on an embedded system

I'm currently working on an embedded project (STM32F103RB, CooCox CoIDE v.1.7.6 with arm-none-eabi-gcc 4.8 2013q4) and I'm trying to understand how malloc() behaves on plain C when the RAM is full.

My STM32 has 20kB = 0x5000Bytes of RAM, 0x200 are used for the stack.

#include <stdlib.h>
#include "stm32f10x.h"

struct list_el {
   char weight[1024];
};

typedef struct list_el item;

int main(void)
{
    item * curr;

    // allocate until RAM is full
    do {
        curr = (item *)malloc(sizeof(item));
    } while (curr != NULL);

    // I know, free() is missing. Program is supposed to crash

    return 0;
}

I would expect malloc() to return NULL as soon as the heap is too small for allocating:

0x5000 (RAM) - 0x83C (bss) - 0x200 (stack) = 0x45C4 (heap)

So when executing the malloc() for the 18th time. One item is 1024=0x400 Bytes large.

But instead the uC calls the HardFault_Handler(void) after the 18th time (not even the MemManager_Handler(void))

Does anybody have an advice how to forecast a malloc() failure - since waiting for a NULL return doesn't seem to work.

Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It does not look like malloc is doing any checks at all. The fault that you get comes from hardware detecting a write to an invalid address, which is probably coming from malloc itself.

When malloc allocates memory, it takes a chunk from its internal pool, and returns it to you. However, it needs to store some information for the free function to be able to complete deallocation. Usually, that's the actual length of the chunk. In order to save that information, malloc takes a few bytes from the beginning of the chunk itself, writes the info there, and returns you the address past the spot where it has written its own information.

For example, let's say you asked for a 10-byte chunk. malloc would grab an available 16-byte chunk, say, at addresses 0x3200..0x320F, write the length (i.e. 16) into bytes 1 and 2, and return 0x3202 back to you. Now your program can use ten bytes from 0x3202 to 0x320B. The other four bytes are available, too - if you call realloc and ask for 14 bytes, there would be no reallocation.

The crucial point comes when malloc writes the length into the chunk of memory that it is about to return to you: the address to which it writes needs to be valid. It appears that after the 18-th iteration the address of the next chunk is negative (which translates to a very large positive) so CPU traps the write, and triggers the hard fault.

In situations when the heap and the stack grow toward each other there is no reliable way to detect an out of memory while letting you use every last byte of memory, which is often a very desirable thing. malloc cannot predict how much stack you are going to use after the allocation, so it does not even try. That is why the byte counting in most cases is on you.

In general, on embedded hardware when the space is limited to a few dozen kilobytes, you avoid malloc calls in "arbitrary" places. Instead, you pre-allocate all your memory upfront using some pre-calculated limits, and parcel it out to structures that need it, and never call malloc again.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...