STM32 堆栈溢出问题
当我们创建稍微复杂一点的系统时,堆栈溢出问题极易出现!
1、一般RAM最后两块空间是堆heap、栈stack,堆从下往上用,栈从上往下用,任意 一个用完都会进入对方空间。
2、如果栈用完,进入堆空间,这个时候系统是不会有任何异常的,也就是说,栈底是没有什么意义的。除非堆和栈指针重叠,否则一切正常,尽管栈指针指向了堆空间。
3、如果栈用完,进入堆的空间,这个时候系统是不会有异常的,但是堆栈会相互修改数据。最难受的就是,栈里面保存的指针地址,一旦被堆空间修改了栈空间中的指针数据,当再次调用占空间中的地址指针时,会跳到无效的内存空间中去,然而这个时候,系统仍然不会报错,但系统运行和数据已经错乱了。
4、如果使用KEIL微库,堆空间用完,再malloc的时候,会得到空指针,但是不会报错。然而如果使用C++的new,这个时候会报错。
以下代码是内存堆栈溢出检测模块。
#ifdef DEBUG
void* operator new(uint size);
void* operator new[](uint size);
void operator delete(void * p);
void operator delete [] (void * p);
#endif
extern uint __heap_base;
extern uint __heap_limit;
void* operator new(uint size)
{
debug_printf(" new size: %d ", size);
void * p = malloc(size);
if(!p)
debug_printf("malloc failed! size=%d ", size);
else
{
debug_printf("0x%08x ", p);
// 如果堆只剩下64字节,则报告失败,要求用户扩大堆空间以免不测
uint end = (uint)&__heap_limit;
if((uint)p + size + 0x40 >= end) debug_printf(" + %d near HeapEnd=0x%08x", size, end);
}
assert_param(p);
return p;
}
void* operator new[](uint size)
{
debug_printf(" new size[]: %d ", size);
void * p = malloc(size);
if(!p)
debug_printf("malloc failed! size=%d ", size);
else
{
debug_printf("0x%08x ", p);
// 如果堆只剩下64字节,则报告失败,要求用户扩大堆空间以免不测
uint end = (uint)&__heap_limit;
if((uint)p + size + 0x40 >= end) debug_printf(" + %d near HeapEnd=0x%08x", size, end);
}
assert_param(p);
return p;
}
void operator delete(void * p)
{
debug_printf(" delete 0x%08x ", p);
if(p) free(p);
}
void operator delete[](void * p)
{
debug_printf(" delete[] 0x%08x ", p);
if(p) free(p);
}```
## 5、我们在实际使用过程中,可能不会像上面一样再去封装检测函数,那这个时候需要我们自己去多多注意相关的问题。
①比如函数调用纵深不宜过深,五个左右为最高。其次,局部变量不要太多太大,尤其是局部数组,大容量的数组定义为全局变量,减少栈空间的占用。
②堆的问题。如果堆空间较小,而需要中间缓存malloc的空间很大,这个时候,很容易导致堆指针指向栈空间,修改栈内数据,导致运行错误。所以,我们要评估我们的malloc缓存空间,在free之前,同时可能存在的最大内存为多少,然后修改启动文件中对应的size,减少系统出错的问题。