嵌入式實時操作系統任務棧溢出檢測原理

任務棧溢出概述

任務棧溢出是緩衝區溢出的一種。 由於緩衝區溢出而使得有用的存儲單元被改寫,往往會引發不可預料的後果。程序在運行過程中,為了臨時存取數據的需要,一般都要分配一些內存空間,通常稱這些空間為緩衝區。如果向緩衝區中寫入超過其本身長度的數據,以致於緩衝區無法容納,就會造成緩衝區以外的存儲單元被改寫,這種現象就稱為緩衝區溢出。緩衝區長度一般與用戶自己定義的緩衝變量的類型有關。

在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會產生內存性保護異常,操作系統就知道任務棧溢出了,一般操作系統會掛起對應的任務並輸出打印信息提示用戶任務棧溢出。


分享到:


相關文章: