如何解决栈溢出

如何解决栈溢出,第1张

解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

尾递归,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

扩展资料

针对堆栈溢出可能造成的计算机安全问题,通常有以下这些防范措施:

1、强制按照正确的规则写代码。

2、通过 *** 作系统使得缓冲区不可执行,从而阻止攻击者植入攻击代码。但由于攻击者并不一定要通过植入代码来实现攻击,同时linux在信号传递和GCC的在线重用都使用了可执行堆栈的属性,因此该方法依然有一定弱点。

3、利用编译器的边界检查来实现缓冲区的保护。该方法使得缓冲区溢出不可能出现,完全消除了缓冲区溢出的威胁,但代价较大,如性能速度变慢。

4、程序指针完整性检查,该方法能阻止绝大多数缓冲区溢出攻击。该方法就是说在程序使用指针之前,检查指针的内容是否发生了变化。

参考资料来源:百度百科-堆栈溢出

参考资料来源:百度百科-栈溢出

*                1. 学习FreeRTOS的任务栈溢出检测方法一(模拟栈溢出)。 *                2. FreeRTOS的任务栈溢出检测方法一说明: *                  a. FreeRTOSConfig.h文件中配置宏定义: *                      #define  configCHECK_FOR_STACK_OVERFLOW  1 *                  b. 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。 *                      void vApplicationStackOverflowHook( TaskHandle_t xTask, *                                                          signed char *pcTaskName ) *                      用户可以在钩子函数里面做一些处理。本实验是在钩子函数中打印出现栈溢出的任务。 *                  c. 这种方法不能保证所有的栈溢出都能检测到。比如任务在执行的过程中发送过栈溢出。任务切换前 *                      栈指针又恢复到了正常水平,这种情况在任务切换的时候是检测不到的。又比如任务栈溢出后,把 *                      这部分栈区的数据修改了,这部分栈区的数据不重要或者暂时没有用到还好,如果是重要数据被修 *                      改将直接导致系统进入硬件异常。这种情况下,栈溢出检测功能也是检测不到的。 *                  d. 本实验就是简单的在任务vTaskUserIF中申请过大的栈空间,模拟出一种栈溢出的情况,溢出后触 *                      发钩子函数,因为我们将溢出部分的数据修改了,进而造成进入硬件异常。  #define  configCHECK_FOR_STACK_OVERFLOW  1 /* ********************************************************************************************************* * 函 数 名: StackOverflowTest * 功能说明: 任务栈溢出测试 * 形    参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void StackOverflowTest(void) {int16_t i uint8_t buf[2048] (void)buf/* 防止警告 *//*  1. 为了能够模拟任务栈溢出,并触发任务栈溢出函数,这里强烈建议使用数组的时候逆着赋值。    因为对于M3和M4内核的MCU,堆栈生长方向是向下生长的满栈。即高地址是buf[2047], 低地址    是buf[0]。如果任务栈溢出了,也是从高地址buf[2047]到buf[0]的某个地址开始溢出。        因此,如果用户直接修改的是buf[0]开始的数据且这些溢出部分的数据比较重要,会直接导致    进入到硬件异常。  2. 栈溢出检测是在任务切换的时候执行的,我们这里加个延迟函数,防止修改了重要的数据导致直接    进入硬件异常。  3. 任务vTaskTaskUserIF的栈空间大小是2048字节,在此任务的入口已经申请了栈空间大小 ------uint8_t ucKeyCode     ------uint8_t pcWriteBuffer[500]     这里再申请如下这么大的栈空间    -------int16_t i -------uint8_t buf[2048]     必定溢出。*/for(i = 2047i >= 0i--){ buf[i] = 0x55vTaskDelay(1) } }/* ********************************************************************************************************* * 函 数 名: vApplicationStackOverflowHook * 功能说明: 栈溢出的钩子函数 * 形    参: xTask        任务句柄 *            pcTaskName  任务名 * 返 回 值: 无 ********************************************************************************************************* */ void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {printf("任务:%s 发现栈溢出\r\n", pcTaskName) } 实验目的: *                1. 学习FreeRTOS的任务栈溢出检测方法二(模拟栈溢出)。 *                2. FreeRTOS的任务栈溢出检测方法二说明: *                  a. FreeRTOSConfig.h文件中配置宏定义: *                      #define  configCHECK_FOR_STACK_OVERFLOW  2 *                  b. 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。 *                      void vApplicationStackOverflowHook( TaskHandle_t xTask, *                                                          signed char *pcTaskName ) *                      用户可以在钩子函数里面做一些处理。本实验是在钩子函数中打印出现栈溢出的任务。 *                  c. 任务创建的时候将任务栈所有数据初始化为0xa5,任务切换时进行任务栈检测的时候检测末尾 *                      的16个字节是否都是0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速度 *                      稍慢些,但是这样就有效的避免了方法一里面的部分情况。不过依然不能保证所有的栈溢出都能检测 *                      到,比如任务栈末尾的16个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检 *                      测不到的。另外任务栈溢出后,任务栈末尾的16个字节没有修改,但是溢出部分的栈区的数据修改 *                      了,这部分栈区的数据不重要或者暂时没有用到还好,如果是重要数据被修改将直接导致系统进入硬 *                      件异常。这种情况下,栈溢出检测功能也是检测不到的。 *                  d. 本实验就是简单的在任务vTaskUserIF中申请过大的栈空间,模拟出一种栈溢出的情况,溢出后触 *                      发钩子函数,因为我们将溢出部分的数据修改了,进而造成进入硬件异常。 #define  configCHECK_FOR_STACK_OVERFLOW  2 函数内容和上面一样: static void StackOverflowTest(void) void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )

gcc的一个编译选项:-fstack-protector,以下是关于这个选项的描述:

-fstack-protector

启用该选项后编译器会产生额外的代码来检测缓冲区溢出,例如栈溢出攻击。这是通过在有缺陷的函数中添加一个保护变量来实现的。这包括会调用到alloca的函数,以及具有超过8个字节缓冲区的函数。当执行到这样的函数时,保护变量会得到初始化,而函数退出时会检测保护变量。如果检测失败,会输出一个错误信息并退出程序。

!注意:在Ubuntu 6.10以及之后的版本中,如果编译时没有指定-fno-fstack-protector, -nostdlib或者-ffreestanding选项的话,那么这个选项对于C,C++,ObjC,ObjC++语言默认是启用的。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8488003.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-17
下一篇 2023-04-17

发表评论

登录后才能评论

评论列表(0条)

保存