野指針 Crash

野指針是指指向一個已刪除的對象或未申請訪問受限內(nèi)存區(qū)域的指針摊鸡。本文說的Obj-C野指針先改,說的是Obj-C對象釋放之后指針未置空,導(dǎo)致的野指針(Obj-C里面一般不會出現(xiàn)未初始化對象的常識性錯誤)际插。

既然是訪問已經(jīng)釋放的對象為什么不是必現(xiàn)Crash呢哥艇?

因為dealloc執(zhí)行后只是告訴系統(tǒng),這片內(nèi)存我不用了胁黑,而系統(tǒng)并沒有就讓這片內(nèi)存不能訪問废封。

現(xiàn)實大概是下面幾種可能的情況:

1.對象釋放后內(nèi)存沒被改動過,原來的內(nèi)存保存完好丧蘸,可能不Crash或者出現(xiàn)邏輯錯誤(隨機(jī)Crash)漂洋。

2.對象釋放后內(nèi)存沒被改動過,但是它自己析構(gòu)的時候已經(jīng)刪掉某些必要的東西力喷,可能不Crash刽漂、Crash在訪問依賴的對象比如類成員上、出現(xiàn)邏輯錯誤(隨機(jī)Crash)冗懦。

3.對象釋放后內(nèi)存被改動過爽冕,寫上了不可訪問的數(shù)據(jù),直接就出錯了很可能Crash在objc_msgSend上面(必現(xiàn)Crash披蕉,常見)颈畸。

4.對象釋放后內(nèi)存被改動過,寫上了可以訪問的數(shù)據(jù)没讲,可能不Crash眯娱、出現(xiàn)邏輯錯誤、間接訪問到不可訪問的數(shù)據(jù)(隨機(jī)Crash)爬凑。

5.對象釋放后內(nèi)存被改動過徙缴,寫上了可以訪問的數(shù)據(jù),但是再次訪問的時候執(zhí)行的代碼把別的數(shù)據(jù)寫壞了,遇到這種Crash只能哭了(隨機(jī)Crash于样,難度大疏叨,概率低)!穿剖!

6.對象釋放后再次release(幾乎是必現(xiàn)Crash蚤蔓,但也有例外,很常見)糊余。


1

仔細(xì)看看上面的關(guān)鍵路徑只有出現(xiàn)被隨機(jī)填入的數(shù)據(jù)是不可訪問的時候才會必現(xiàn)Crash秀又。

所以把這一隨機(jī)的過程變成不隨機(jī)的過程。對象釋放后在內(nèi)存上填上不可訪問的數(shù)據(jù)贬芥,其實這種技術(shù)其實一直都有吐辙,xcode的Enable Scribble就是這個作用。


2

但是有個問題:這個方法不能放在測試那邊用蘸劈!因為總不能讓測試裝了xcode來測試吧昏苏?

于是我們自己動手實現(xiàn)一個,這個過程中我們要解決幾個問題:

1.怎么在內(nèi)存釋放后填上不可訪問的數(shù)據(jù)昵时?

內(nèi)存釋放很可能不在我們的代碼中捷雕。為此我們需要hook對象釋放的接口,內(nèi)存時候之后馬上執(zhí)行我們的破壞工作壹甥。

2.我們要重寫對象釋放的接口救巷,重寫哪個呢?

NSObject的dealloc句柠、runtime的 object_dispose浦译,C的free應(yīng)該都是可以,但是各有優(yōu)點溯职,我選擇的是覆蓋面最廣的free精盅,free是C的函數(shù),重寫了它之后還可以順帶解決一部分C的野指針問題谜酒。

3.怎么重寫叹俏?

重寫C的接口場景的有兩種:

a.替換系統(tǒng)動態(tài)庫

b.hook

替換動態(tài)庫太麻煩,還不知道行不行得通僻族;hook我們就找現(xiàn)成的fishhook粘驰,github里面找的,但現(xiàn)成的代碼需要防止代碼沖突述么。

4.填充的不可訪問的數(shù)據(jù)的長度怎么確定蝌数?

獲取內(nèi)存長度的接口不在標(biāo)準(zhǔn)庫中,好在在Mac和iOS中可以用malloc_size就可以度秘。

5.填什么顶伞? ? ? ? ? ? ??和xcode一樣,填0x55。

上hook后的free代碼:

[size=0.85em]void safe_free(void* p){? ? size_t memSiziee=malloc_size(p);? ? memset(p, 0x55, memSiziee);? ? orig_free(p);? ? return;}

測試一下唆貌,出現(xiàn)了和Enable Scribble一樣的Crash滑潘!

以上就是一種在內(nèi)存釋放后填充0x55使野指針后數(shù)據(jù)不能訪問,從而使某些野指針從不必現(xiàn)Crash變成了必現(xiàn);



3

其實這就是上一篇文中留下了幾個問題之一锨咙,如果我們填充0x55后內(nèi)存又被別的內(nèi)存覆蓋了众羡,最終還是會出現(xiàn)隨機(jī)Crash。而在真實環(huán)境中蓖租,這種情況是非常常見的。

我們再梳理一下這個過程:

1.我們在即將要釋放的填了0x55羊壹,之后調(diào)用了free真正釋放蓖宦,內(nèi)存被系統(tǒng)回收。

2.這個時候系統(tǒng)隨時可能把這片內(nèi)存給別的代碼使用油猫,也就是說我們的0x55被再次寫上隨機(jī)的數(shù)據(jù)(在這里再強(qiáng)調(diào)一下稠茂,訪問野指針是不會Crash的,只有野指針指向的地址被寫上了有問題的數(shù)據(jù)才會引發(fā)Crash)情妖。

3.假如釋放的內(nèi)存上又填上了另一個對象的指針睬关,而那個對象也有同樣的一個方法,那很可能只是邏輯上有問題毡证,并不會直接Crash电爹,甚至悄無聲息地像什么事情都沒發(fā)生一樣。(這個地方可能會發(fā)生多種情況料睛,可以參考之上一篇文章中的圖)

沒有發(fā)生Crash可不是好事丐箩,因為這種情況如果后續(xù)再Crash,問題就非常難查恤煞,因為你看到的Crash棧很可能和出錯的代碼完全沒有關(guān)聯(lián)屎勘。既然這個問題這么棘手,最好還是和之前一樣居扒,讓這個Crash提前暴露概漱。

首先,我們要解決的問題就是怎么讓系統(tǒng)不再往這片釋放的內(nèi)存上亂放東西喜喂。

要控制底層內(nèi)存管理機(jī)制讓它不使用這些內(nèi)存可能很困難瓤摧。但是,我們變通一下夜惭,簡單粗暴地姻灶,我們干脆就不釋放這片內(nèi)存了。也就是當(dāng)free被調(diào)用的時候我們不真的調(diào)用free诈茧,而是自己保留著內(nèi)存产喉,這樣系統(tǒng)不知道這片內(nèi)存已經(jīng)不需要用了,自然就不會被再次寫上別的數(shù)據(jù)

為了防止系統(tǒng)內(nèi)存過快耗盡,還需要額外多做幾件事:

1.自己保留的內(nèi)存大于一定值的時候就釋放一部分曾沈,防止被系統(tǒng)殺死这嚣。

2.系統(tǒng)內(nèi)存警告的時候,也要釋放一部分內(nèi)存塞俱。

4

在safe_free以及它調(diào)用的函數(shù)里面盡量不要再用帶鎖的函數(shù)姐帚,不然很容易導(dǎo)致死鎖。

加上這個代碼之后APP的內(nèi)存占用會增大不少障涯,拿過來測試可以罐旗,但萬萬不能放在正式的發(fā)布版本中

關(guān)于性能問題唯蝶,我的機(jī)器是iPhone5九秀,跑在App里面運行,還算流暢(不同App性能可能會有些不同)粘我。

可能由于鎖的存在鼓蜒,會使cpu線程切換變得頻繁,這樣多線程的問題Crash率也可能會提升(最近遇到一個多線程引起的Crash很難重現(xiàn)征字,但我加了這個代碼后就變成了必現(xiàn)Crash)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末都弹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匙姜,更是在濱河造成了極大的恐慌畅厢,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搁料,死亡現(xiàn)場離奇詭異或详,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)郭计,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門霸琴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昭伸,你說我怎么就攤上這事梧乘。” “怎么了庐杨?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵选调,是天一觀的道長。 經(jīng)常有香客問我灵份,道長仁堪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任填渠,我火速辦了婚禮弦聂,結(jié)果婚禮上鸟辅,老公的妹妹穿的比我還像新娘。我一直安慰自己莺葫,他們只是感情好匪凉,可當(dāng)我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捺檬,像睡著了一般再层。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堡纬,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天聂受,我揣著相機(jī)與錄音,去河邊找鬼烤镐。 笑死饺饭,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的职车。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼鹊杖,長吁一口氣:“原來是場噩夢啊……” “哼悴灵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骂蓖,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤积瞒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后登下,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茫孔,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年被芳,在試婚紗的時候發(fā)現(xiàn)自己被綠了缰贝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡畔濒,死狀恐怖剩晴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侵状,我是刑警寧澤赞弥,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站趣兄,受9級特大地震影響绽左,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜艇潭,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一拼窥、第九天 我趴在偏房一處隱蔽的房頂上張望戏蔑。 院中可真熱鬧,春花似錦闯团、人聲如沸辛臊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彻舰。三九已至,卻和暖如春候味,著一層夾襖步出監(jiān)牢的瞬間刃唤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工白群, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留尚胞,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓帜慢,卻偏偏與公主長得像笼裳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子粱玲,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容