嵌入式实时操作系统任务栈溢出检测原理

任务栈溢出概述

任务栈溢出是缓冲区溢出的一种。 由于缓冲区溢出而使得有用的存储单元被改写,往往会引发不可预料的后果。程序在运行过程中,为了临时存取数据的需要,一般都要分配一些内存空间,通常称这些空间为缓冲区。如果向缓冲区中写入超过其本身长度的数据,以致于缓冲区无法容纳,就会造成缓冲区以外的存储单元被改写,这种现象就称为缓冲区溢出。缓冲区长度一般与用户自己定义的缓冲变量的类型有关。

在C语言中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。在任务中的局部变量是直接从任务栈中分配的,静态局部变量不在线程栈中,所以如果函数调用过多或者在函数中定义了大的数组或者变量容易导致局部变量占用空间超过栈空间,导致任务栈溢出。因此尽量避免在函数中定义占用空间较大的变量,如果需要可通过malloc函数从堆中分配。

各个嵌入式实时操作系统中系统默认任务栈大小各不相同。有的系统默认任务栈为4K,有的为8K,针对嵌入式系统而言,内存资源相对紧张,如果任务栈设置太大会导致内存资源的浪费。所以一般创建任务时提供参数让用户可以设置任务栈大小和任务栈地址,如果创建任务时使用的栈地址的默认值为NULL,系统会为任务分配堆栈。

国军标GJB7714(军用嵌入式实时操作系统应用编程接口)接口中定义了四个任务栈相关接口,用于用户设置和获取任务栈大小和任务栈地址。

int pthread_attr_setstacksize(pthread_attr_t *attr,size_t stacksize);

该接口用于设置任务属性对象 attr 中的 stacksize 属性,该属性指定了创建任务栈需分配的长度(字节)。

int pthread_attr_getstacksize(const pthread_attr_t *attr,size_t *stacksize);

该接口用于获取任务属性对象 attr 中的任务创建的 stacksize 属性。

int pthread_attr_setstackaddr(pthread_attr_t *attr,void *stackaddr);

该接口用来设置任务属性对象 attr 中的 stackaddr 属性。 stackaddr 属性指定了任务栈的存储位置,存储区域的大小最小为 PTHREAD_STACK_MIN。如果用户设置了任务栈,那么用户负责任务栈对应内存资源的回收。

int pthread_attr_getstackaddr(const pthread_attr_t *attr ,void **stackaddr);

该接口用于获取任务属性对象 attr 中的 stackaddr 属性,并存放在参数 stackaddr 指定的地址中。任务的 stackaddr 属性指定了任务栈的存储位置,最小为PTHREAD_STACK_MIN。

实时操作系统任务栈溢出检测原理

任务堆栈一但溢出,意味着系统的崩溃,因此操作系统提供栈溢出检查非常有必要。当前大多数CPU都具备MMU或者MPU,对任务栈溢出的检测十分简单。

嵌入式实时操作系统任务栈溢出检测原理

通过设置栈顶部分空间为只读属性(即红色部分),当任务栈溢出访问红色部分空间时,MMU会产生内存性保护异常,操作系统就知道任务栈溢出了,一般操作系统会挂起对应的任务并输出打印信息提示用户任务栈溢出。


分享到:


相關文章: