栈溢出情况研究

2012-05-07 22:56:38

    

最近了解了RTOS的核心就是用户自己设置栈空间。那么为什么要用户自己设置栈空间呢?自己思考了下,自认为答案是自己设置栈空间存在优点。优点之一应该就是能防止栈溢出导致的程序跑飞吧!一般RTOS创建一个task时候都会要求输入栈空间大小。如何计算栈空间要分配多少,一个调用函数及函数中的参数,局部变量都是放在栈空间的中,基本就是这么评估的。今天主要研究一下栈溢出的现象及如何在调试中发现栈溢出。

一,名词解释

1,  栈溢出。

栈的size为0x100=256字节。栈地址的bottom为0x2100,而首地址为0x2000。

根据默认的CW5.1生成的工程就是如此的默认设置。可以参考prm文件。

栈溢出:就是指SP(堆栈指针)指向的地址超出了此范围就做栈溢出。

栈溢出分类:top溢出。

            Bottom溢出。

 

二,情况分析

1,  顶端溢出1,代码运行前局部变量空间已经溢出。

代码如下

#define NUM 255 //253,252

 

unsigned char g_testa,g_testb;

unsigned char g_result;

void main(void) {

unsigned int i;

unsigned char l_testa[NUM];

 

for (i=0;i<NUM;i++)

  l_testa[i]=i;

g_result=l_testa[NUM-1];

}

溢出分析:局部变量为257字节大于256字节。SP地址值小于0x2000, g_top,g_bot读数都不正确。

 栈溢出情况研究

 

 2,  顶端溢出2,代码运行前局部变量空间没有溢出。

代码如下:

#include <hidef.h>      /* common defines and macros */

#include "derivative.h" /* derivative-specific definitions */

 

//Data type

typedef unsigned char uint8;

//Macro

//#define TopOverFlow            //OverFlow type.

//#define BotOverFlow

#if defined(TopOverFlow)

  typedef unsigned int type_i;

  #define NUM 255              //Array Lenth

#else

  typedef unsigned char type_i;

  #define NUM 255

#endif 

//Global  var

uint8 g_result;    //not need it

uint8 g_top,g_bot; //Save value of Array[top] and Arry[Bottom],located Address:FE2100.FE2101

 

//Function

void main(void)

{

  //Local

  type_i i;                  //Local var,save in stack temporary

  uint8 l_testa[NUM];   //Local var,save in stack temporary

  //Test

  for ( i=0; i<NUM; i++ )

  {

    l_testa[i]  =  (uint8)i;

  }

  g_top  =  l_testa[0];

  g_bot  =  l_testa[NUM-1];

}

溢出分析:局部变量为256字节等于栈空间的大小,但是由于调用main函数,所以会占用3个字节0xFE C0 0F,所以,SP地址值小于0x2000,栈顶溢出。Top值预期为0,但是读数为90。

 栈溢出情况研究

 

 

3,  顶底溢出。由于栈是从底到顶增长的。所以要向下溢出,只能通过数组溢出。

#include <hidef.h>      /* common defines and macros */

#include "derivative.h" /* derivative-specific definitions */

 

//Data type

typedef unsigned char uint8;

//Macro

//#define TopOverFlow            //OverFlow type.

#define BotOverFlow

#if defined(TopOverFlow)

  typedef unsigned int type_i;

  #define NUM 255              //Array Lenth

#elif defined(BotOverFlow)

  typedef unsigned char type_i;

  #define NUM 10

#else

  typedef unsigned char type_i;

  #define NUM 255

#endif 

//Global  var

uint8 g_result;    //not need it

uint8 g_top,g_bot; //Save value of Array[top] and Arry[Bottom],located Address:FE2100.FE2101

 

//Function

void main(void)

{

  //Local

  type_i i;                  //Local var,save in stack temporary

  uint8 l_testa[NUM];   //Local var,save in stack temporary

  //Test

#if defined(BotOverFlow)

  for ( i=1; i<NUM+5; i++ )

  {

    l_testa[i]  =  (uint8)i-1;

  }

#else

  for ( i=0; i<NUM; i++ )

  {

    l_testa[i]  =  (uint8)i;

  }

#endif

  g_top  =  l_testa[0];

  g_bot  =  l_testa[NUM-1];

}

溢出分析:代码运行前栈是没有溢出的,数组分配空间期望值为10个字节+1个字节的局部变量i。然后代码运行后,for循环数组赋值超出了数组的上限,则赋值继续进行,把数组栈地址下面的局部变量(main的入栈函数地址)及g_top,g_bot的全局变量给覆盖了。

 

 栈溢出情况研究

 

兼容三种情况,最终代码改成如下

#include <hidef.h>      /* common defines and macros */

#include "derivative.h" /* derivative-specific definitions */

 

//Data type

typedef unsigned char uint8;

//Macro

//Select one of next list to test OverFlow

#define TopOverFlow1            //OverFlow type1.

//#define TopOverFlow2            //OverFlow type2.

//#define BotOverFlow           //OverFlow type3.

#if defined(TopOverFlow1)

  typedef unsigned int type_i;

  #define NUM 255              //Array Lenth

#elif defined(BotOverFlow)

  typedef unsigned char type_i;

  #define NUM 10

#else

  typedef unsigned char type_i;

  #define NUM 255

#endif 

//Global  var

uint8 g_result;    //not need it

uint8 g_top,g_bot; //Save value of Array[top] and Arry[Bottom],located Address:FE2100.FE2101

 

//Function

void main(void)

{

  //Local

  type_i i;                  //Local var,save in stack temporary

  uint8 l_testa[NUM];   //Local var,save in stack temporary

  //Test

#if defined(BotOverFlow)

  for ( i=1; i<NUM+5; i++ )

  {

    l_testa[i]  =  (uint8)i-1;

  }

#else

  for ( i=0; i<NUM; i++ )

  {

    l_testa[i]  =  (uint8)i;

  }

#endif

  g_top  =  l_testa[0];

  g_bot  =  l_testa[NUM-1];

}

 

但是发现一个问题。#define TopOverFlow1情况和我之前一开始的代码运行情况不同了。最终g_top为0,g_bot为1,并且进入一次for循环。不过g_bot为什么为1?没找到来源。

 

上一篇:适用于单片机的小型类shell的命令行软件


下一篇:keil 编译器V6 定义函数在ram中运行-和在指定地址定义常量