FreeRTOS内核原生提供了两套开箱即用的栈溢出检测方案,通过FreeRTOSConfig.h里的configCHECK_FOR_STACK_OVERFLOW宏即可开启,适配不同的调试阶段:
1. 轻量级
将configCHECK_FOR_STACK_OVERFLOW = 1,则进入轻量级栈水印检测。
系统在任务创建初期,会把整块栈空间全部填充成固定的标记值,每次任务切换时,内核只会校验栈底部的几个标记字节有没有被修改。如果标记值被改动,就说明栈已经触碰到了边界,此时会自动调用栈溢出钩子函数。 这套方案的优势是系统开销极低,几乎不会影响任务切换的实时性,适合项目常规开发阶段长期开启。
缺点是只能检测到栈底被踩踏的场景,对于栈的小幅溢出、顶部局部覆盖的情况存在漏检概率。
2. 全量高
将configCHECK_FOR_STACK_OVERFLOW = 2,则进入全量高精度栈检测。
这是精度更高的检测模式,不仅保留了水印标记检测逻辑,还会在每次任务切换时完整校验整块栈空间的数据完整性,同时自动统计任务运行过程中的栈峰值占用情况,能识别轻微溢出、局部内存踩踏等几乎所有异常场景。
缺点是会带来小幅的任务切换开销,适合集中排查栈溢出问题、系统功能测试阶段开启,量产版本可以关闭该功能来提升系统实时性。
栈溢出hook实现
当我们在RTOS中开启检测后,必须自己实现hook函数才能拿到溢出信息,这里简单代码如下:
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
/* 打印输出溢出任务的名字、句柄等到调试日志 */
jlog_error("Stack Overflow detected! Task name: %s\r\n", pcTaskName);
while(1);
}注意钩子函数可能在中断上下文里被调用,不要在这里执行太复杂的操作。
我要赚赏金
