栈空间溢出

前言

嵌入式工程师们免不了和堆栈打交道,深入理解了这两个东西,才能从代码编写时就考虑清楚内存管理,避免到后期出现各种莫名其妙的问题。

最近在使用CC2530时也遇到了一些问题,怀疑跟栈空间溢出有关,于是做了一次梳理。可能有些理解还不到位,等了解了再修正。

本文是以CC2530为例做了测试,我们可以借鉴到其他单片机上。

所谓栈空间,就是一块内存空间。而溢出,就是使用的内存区域超过了这块空间。占用栈空间的是局部变量。

TI的FAE说CC2530的栈空间大小为223字节左右,最好不要超出。我实际测试,超过250就会崩溃,表现为打印函数出不来。可以这么理解,超过223字节的时候,栈空间溢出了,此时有些内存区域出现了覆盖等不良情况,但还没影响到打印的这部分;但栈使用超过250字节时,效果就很明显了,打印函数都被波及。

转载请注明:http://blog.csdn.net/sadshen/

一、栈溢出的几种现象

我把自己目前认为的可导致栈溢出的行为,给列了出来。1.1和1.2都很容易理解。1.3可能会被忽视,但其实理一理,发现并不难理解,因为子函数在占用栈空间时,其外部的函数并没有释放出栈空间。

1.1 单个局部变量的溢出

void main(void)
{
  uint8 tmp[250] = {0};
}

1.2 多个局部变量的溢出

void main(void)
{
  uint8 tmp1[120] = {0};
  uint8 tmp2[130] = {0};
}

1.3 嵌套函数的溢出

void Fun(void)
{
  uint8 tmp[120] = {0};
}

void main(void)
{
  uint8 tmp[130] = {0};
  Fun();
}

1.4 传递参数溢出

void Fun(struct PARA_T)
{
  ;
}

二、栈溢出的预防及优化

2.1 划分出子函数

如上面的1.3,如果可以优化成如下的多个子函数就可以避免栈溢出了。每个子函数在作用域结束时,其申请的栈空间会做释放。子函数处理是将局部变量放在同级的函数里,其实是在时间上将栈空间使用给叉开。我的同事之前不懂这点,以为我们的程序有大问题。

void Fun_120(void)
{
  uint8 tmp[120] = {0};
}

void Fun_130(void)
{
  uint8 tmp[130] = {0};
}

void main(void)
{
  Fun_120();
  Fun_130();
}

2.2 注意嵌套的总深度

在多级嵌套的时候,如果出现大的局部变量的时候,一定要格外小心。子函数的栈使用是在母函数的使用基础上增加的,空间上是累加的,必须要注意。

2.3 常用的临时变量可转化为静态变量

如1.3中,若FUN()中的tmp[120]经常需要调用,不妨可以将其转化为静态变量。让其转为占用RAM资源,避免其经常申请栈资源,冷不丁给你一个溢出。

2.4 传递参数时尽量用指针

如1.4中,直接传递结构体,可以改为传递结构体的指针。

void Fun(struct *PARA_T)

{

;

}

总结

大概就是这样吧。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-09 02:00:50

栈空间溢出的相关文章

初学JAVA——栈空间堆空间的理解

1.Person pangzi;    //这是在“开拓空间”于栈空间 pangzi=new Person();    //这是赋值于堆空间 上两步就是在做与空间对应的事. 2.值类型直接存入栈空间,如AF,引用类型存入堆空间,在栈空间存有“索引地址”,如当需要B时,在栈空间寻找“索引地址”后对应寻找堆空间的“详细内容”. 故,值类型“快”,引用类型“灵活”. 例String S = “ABCDEFG........Z",则S对应栈空间,“ABCDEFG........Z"对应堆空间.

linux查看修改线程默认栈空间大小(ulimit -s)

linux查看修改线程默认栈空间大小 ulimit -s 1.通过命令 ulimit -s 查看linux的默认栈空间大小,默认情况下 为10240 即10M 2.通过命令 ulimit -s 设置大小值 临时改变栈空间大小:ulimit -s 102400, 即修改为100M 3.可以在/etc/rc.local 内 加入 ulimit -s 102400 则可以开机就设置栈空间大小 4.在/etc/security/limits.conf 中也可以改变栈空间大小: #<domain> &l

C语言中函数调用过程(如何管理栈空间)

ps:先做草稿,以后有时间再整理并贴图,:) 主要是利用栈底寄存器(ebp).栈顶寄存器(esp)跟eax寄存器(存储返回值)来实现. 假设P调用Q: P() { Q(1,2); } 1.调用前准备,将Q的参数放到栈中(非push) mov $1, (%esp) mov $2, 4(%esp) 2.调用call 0x12345678 (Q的地址) 首先将函数的返回地址(call语句后的那条指令的地址)进栈, 然后跳到0x12345678执行Q的代码. 3.将旧的ebp进栈(用于退出Q时还原) p

Linux栈空间检测代码

今天终于知道linux栈空间了.因为写了个简单程序,可以让linux的栈空间耗尽,然后出现core dumped,即栈溢出 代码如下: #include <stdio.h> void overFlow() { long i; printf("&i  : %p\n",&i); overFlow(); } int main() { OverFlow(); } 运行程序 ./out > out.log 栈地址是从高到低,所以用第一个减去最后一个地址,就能得到

你必须知道的指针基础-8.栈空间与堆空间

一个由C/C++编译的程序占用的内存分为以下几个部分: 1.栈区(stack):又编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构的栈. 2.堆区(heap):一般是由程序员分配释放,若程序员不释放的话,程序结束时可能由OS回收,值得注意的是他与数据结构的堆是两回事,分配方式倒是类似于数据结构的链表. 3.全局区(static):也叫静态数据内存空间,存储全局变量和静态变量,全局变量和静态变量的存储是放一块的,初始化的全局变量和静态变量放一块区域,没有初始化的在相邻

FreeRTOS 查询任务 剩余的栈空间的 方法

From:http://www.cnblogs.com/suozhang/p/5301054.html 1.官方文档提供了   函数  用来查询  任务 剩余   栈 空间,首先是看官方的文档解释(某位大神 翻译 的 官方 文档.) 参数解释:     xTask:被查询任务的句柄——欲知如何获得任务句柄,详情请参见API 函数xTaskCreate()的参数pxCreatedTask.如果传入 NULL 句柄,则任务查询的是自身栈空间的高水线. 返回值: 任务栈空间的实际使用量会随着任务执行和

关于栈空间和堆空间的问题

操作系统对于内存的两种管理方式 如鹏网 <C语言也能干大事>http://www.rupeng.com/Courses/Index/12 第三章透彻讲指针 之  第 15 节: 栈空间 平时我们定义的变量都是分布在栈空间里,如下面的程序所示 1 #include <stdio.h> 2 int main(int argc, char *argv[]) 3 { 4 int i=5; 5 char s[] = "afasdfsfwfw"; 6 return 0; 7

栈空间大小限制

一. 查看栈大小限制 不同系统的栈空间大小不同,可通过如下方法查看系统栈大小限制 cat /proc/1/limits 该文件列出了系统资源限制情况(ubuntu 16.04): Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max s

0xC0000005;Access Violation(栈区空间很宝贵, linux上栈区空间默认为8M,vc6下默认栈空间大小为1M)

写C/C++程序最怕出现这样的提示了,还好是在调试环境下显示出来的,在非调试状态就直接崩溃退出. 从上述汇编代码发现在取内存地址 eax+38h 的值时出错, 那说明这个地址非法呗, 不能访问, 一般是访问了空指针引起的. 直接调用QList::append()方法也会出错了, 此时汇编也指向的是在读取内存 ebp-8 时出错. 这段代码运行背景是在栈上申请了很多缓冲区,然后缓冲区在不停添加内容, 直到某一阶段程序崩溃. 由于栈区空间很宝贵, linux上栈区空间默认为8M,vc6下默认栈空间大