我正在使用 Cross ARM GCC 工具链在 Kinetis TWRK70M120 上调试裸机项目。 (Kinetis Design Studio)
我有一个问题:
为什么 malloc() 在超出堆大小时不返回 NULL 指针?
这怎么可能?
我没想到会这样,但在分析了不同的情况后发现,只有当没有足够的空间时,malloc()才会返回NULL指针在堆中或堆栈中。我在 StackOverflow 论坛上发现了这个问题:
When does malloc return NULL in a bare-metal environment?
他们正在讨论 HEAP 和 STACK 冲突,什么可能与这个问题有关。虽然,我不确定我们是否可以谈论冲突,即使两个(堆栈和堆)地址范围都被正确管理(在我看来)。例如,如果我定义一个包含 10 个整数的本地数组,它将占用堆栈顶部的 cca 40-48 个字节。这意味着这部分堆栈不可用于动态分配,并且仅当您尝试分配大于 cca HEAP+STACK-48 字节的地址空间时,malloc() 返回 NULL。在我的项目中 0x400 + 0x500 - 48bytes(提到的数组) - 其他局部变量。我真的不确定这是否是常见行为,或者我只是没有正确理解 malloc() 函数。
这是我用于测试 malloc 函数的代码。
堆大小 = 0x20000400
堆大小 = 0x20000500
这是我用来测试 malloc 函数的代码。
#include "MK70F12.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
extern uint32_t __HeapBase;
extern uint32_t __HeapLimit;
extern uint32_t __StackTop;
extern uint32_t __StackLimit;
//MY TEST
static int j=0, k=0, i=0; //Global variables
int main(void)
{
//For testing purposes I defined STACK = 0x0x00000500 (cca 1280bytes) and
//HEAP = 0x0x00000400 (cca 1024bytes) what means that
//I have approximately (theoretically) 2304 bytes available.
/* Write your code here */
void* pHeapBase = ((void*)&__HeapBase);
void* pHeapLimit= ((void*)&__HeapLimit);
void* pStackTop = ((void*)&__StackTop);
void* pStackLimit= ((void*)&__StackLimit);
//---------------------------------------------------------------------------------------------------------
char* pMalloc_data1=(char*)malloc(1200*sizeof(char)); //Dynamically allocated array which size is bigger
//than the HEAP size (beginning address in HEAP space).
//It seems, when it overruns the heap size it doesn't
//return NULL, but it continues growing into the stack.
//Malloc returns NULL pointer only if there is
//no space available neither in the HEAP nor in the STACK.
if (pMalloc_data1==NULL)
{
return(1); //Allocation failed
}
for(j=0;j<1200;j++)
{
*(pMalloc_data1+j)='a'; //just some initialization with character
//memory filled with 1200 chars
//address range 0x200000a8 - 0x20000559(0x20000558?)
}
//---------------------------------------------------------------------------------------------------------
int *pMalloc_data2 = (int*)malloc(10*sizeof(int)); //Dynamically allocated array
//(beginning address in STACK space)!!!.
//Malloc returns NULL pointer only if there is
//no space available in the STACK (HEAP is already full).
if (pMalloc_data2==NULL)
{
return(1);
}
for(i=0;i<10;i++)
{
*(pMalloc_data2+i)=i+4000; //memory filled with 200 integers
//address range 0x20000560 - (theoretically)0x20000588 (0x20000590?)
}
int array[10] = {10,15,78,62,80,6528,8,58,64,984}; //Local static array => in STACK
//For this array is space in STACK reserved
//at the beginning of the program
free(pMalloc_data1);
free(pMalloc_data2);
for(;;)
{
k++;
}
return 0;
}
最佳答案
在裸机环境中,您需要实现 _sbrk
功能如下:
#include <unistd.h>
#include <errno.h>
// start and end of Heap as defined in the linker script (_heap_start < _heap_end)
extern unsigned int const _heap_start;
extern unsigned int const _heap_end;
/**
* @brief Changes data segment space allocation (it may be called by malloc) .
* @details It may be called by malloc() .
* @param[in] increment Number of byte to be allocated .
* @return On success the previous program break (program break = beginning of available mem) .
On error -1 .
*/
void *_sbrk(ptrdiff_t increment)
{
static void *heap_free = 0;
void *heap_prev;
if (heap_free == 0)
{
heap_free = (void *) &_heap_start; // First call
}
if ((heap_free + increment) < ((void *) &_heap_end))
{
heap_prev = heap_free;
heap_free += increment;
return heap_prev;
}
else
{
errno = ENOMEM;
return ((void *) -1);
}
}
在 K70 上,堆栈向下增长,而堆向上增长。有了这个功能,只要设置_heap_end = _stack_end
就永远不会发生碰撞。在你的链接器脚本中,并且你的堆栈大小足够大。
当您拥有操作系统时,_sbrk
由它提供。
关于c - 当超出堆(裸机)时,malloc() 不会返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41977122/