簡介
本文介紹了如下內(nèi)容
- 棧的概念
- 為什么會發(fā)生棧溢出
- 棧溢出的幾種栗子
- 怎么預(yù)防和發(fā)現(xiàn)棧溢出锈麸。
什么是棧趾徽?
從數(shù)據(jù)結(jié)構(gòu)來說:棧(stack)又名堆棧侧巨,它是一種運算受限的線性表。限定僅在表尾進(jìn)行插入和刪除操作的線性表躯枢。這一端被稱為棧頂则吟,相對地,把另一端稱為棧底锄蹂。向一個棧插入新元素又稱作進(jìn)棧氓仲、入棧或壓棧得糜,它是把新元素放到棧頂元素的上面敬扛,使之成為新的棧頂元素;從一個棧刪除元素又稱作出棾叮或退棧啥箭,它是把棧頂元素刪除掉,使其相鄰的元素成為新的棧頂元素治宣。
在計算機系統(tǒng)中:棧則是一個具有以上屬性的動態(tài)內(nèi)存區(qū)域急侥。程序可以將數(shù)據(jù)壓入棧中,也可以將數(shù)據(jù)從棧頂彈出侮邀。在i386機器中坏怪,棧頂由稱為esp的寄存器進(jìn)行定位。壓棧的操作使得棧頂?shù)牡刂窚p小豌拙,彈出的操作使得棧頂?shù)牡刂吩龃蟆?/p>
-
棧在程序的運行中有著舉足輕重的作用陕悬。最重要的是棧保存了一個函數(shù)調(diào)用時所需要的維護信息,這常常稱之為堆棧幀或者活動記錄按傅。堆棧幀一般包含如下幾方面的信息:
- 臨時變量:包括函數(shù)的非靜態(tài)局部變量以及編譯器自動生成的其他臨時變量捉超。
- 函數(shù)的返回地址和參數(shù)
什么是棧溢出胧卤?
棧溢出就是緩沖區(qū)溢出的一種。 由于緩沖區(qū)溢出而使得有用的存儲單元被改寫,往往會引發(fā)不可預(yù)料的后果拼岳。程序在運行過程中枝誊,為了臨時存取數(shù)據(jù)的需要,一般都要分配一些內(nèi)存空間惜纸,通常稱這些空間為緩沖區(qū)叶撒。如果向緩沖區(qū)中寫入超過其本身長度的數(shù)據(jù),以致于緩沖區(qū)無法容納耐版,就會造成緩沖區(qū)以外的存儲單元被改寫祠够,這種現(xiàn)象就稱為緩沖區(qū)溢出。緩沖區(qū)長度一般與用戶自己定義的緩沖變量的類型有關(guān)粪牲。棧溢出就是緩沖區(qū)溢出的一種古瓤。
iOS/Mac棧的大小是多少?
- iOS上主線程椣傺簦空間大小為1MB
- iOS上子線程椔渚空間大小為512KB
- Mac OS上主線程棧大小為8MB
- 對于子線程,線程的棧大小是在線程創(chuàng)建的時候就創(chuàng)建好的亭引,但是只有實際使用到的時候才會分配到具體內(nèi)存绎速;同時,子線程能夠允許的最小棧大小為16KB焙蚓,且棧的大小必須是4KB的整數(shù)倍纹冤。
哪些情況會造成棧溢出
- 棧上變量直接分配內(nèi)存長度超過棧空間大小,如下
int buf[1024*1024] = {0};
對應(yīng)的崩潰日志主届,一般情況下遇見有Stack Guard
的關(guān)鍵字赵哲,就標(biāo)明棧溢出了
- 間接使用操作棧上內(nèi)存超限的函數(shù)待德,包括但不限于以下函數(shù)
void *memcpy(void *__dst, const void *__src, size_t __n);
void *memmove(void *__dst, const void *__src, size_t __len);
char *strcpy(char *__dst, const char *__src);
char *strncpy(char *__dst, const char *__src, size_t __n);
舉個栗子:
void function1(char *str){
int32_t maxsize = 100*1024*1024;
char buffer[maxsize];
//strcpy(buffer, str);
memcpy(buffer, str, maxsize);
}
char *a = malloc(1024*1024);
function1(a);
來個崩潰日志君丁,關(guān)鍵字還是Stack Guard
哦。
- 無限遞歸調(diào)用,見如下斐波那契數(shù)列函數(shù)遞歸實現(xiàn)
int fibonacci(int n){
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return fibonacci(n) * fibonacci(n - 1);
}
再來個崩潰日志給大家瞧瞧将宪,不要錢哦绘闷,關(guān)鍵字還是Stack Guard
!
_
怎么避免棧溢出崩潰较坛?
- 棧上申請內(nèi)存不要超過512KB印蔗,建議超過100KB以上的內(nèi)存申請,都使用堆上的內(nèi)存分配方式丑勤,
malloc
,calloc
等 - 使用操作內(nèi)存讀寫的系統(tǒng)函數(shù)時华嘹,保證大內(nèi)存的內(nèi)存操作在堆上進(jìn)行
- 避免使用遞歸,所有的遞歸都可以使用循環(huán)實現(xiàn)法竞。即使不得不使用遞歸耙厚,也要對遞歸調(diào)用層次做優(yōu)化和控制(感謝@老青菜提出的寶貴意見)强挫。
參考文獻(xiàn)
作者:落葉情思 鏈接:https://juejin.cn/post/6902668468991524871