2016-12-05 58 views
1

所以我有一個有5個參數的方法。正如預期的那樣,寄存器版權狀態,它被稱爲前:在取消引用寄存器(%r11)時崩潰了objc_msgSend,但我不明白爲什麼

$rdi: The receiver 
$rsi: the selector for the method 
$rdx: first arg 
$rcx: second arg 
$r8: third arg 
$r9: fourth arg 
$r10 fifth arg 

在這個方法中,它做的第一件事是調用另一個Objective-C的方法

這反過來調用objc_msgSend(見偏移+58):

MyApp`-[GTMOAuth2WindowController webView:resource:willSendRequest:redirectResponse:fromDataSource:]: 
    0x10044a1a0 <+0>: pushq %rbp 
    0x10044a1a1 <+1>: movq %rsp, %rbp 
    0x10044a1a4 <+4>: subq $0x40, %rsp 
    0x10044a1a8 <+8>: movq 0x10(%rbp), %rax 
    0x10044a1ac <+12>: movq %rdi, -0x10(%rbp) 
    0x10044a1b0 <+16>: movq %rsi, -0x18(%rbp) 
    0x10044a1b4 <+20>: movq %rdx, -0x20(%rbp) 
    0x10044a1b8 <+24>: movq %rcx, -0x28(%rbp) 
    0x10044a1bc <+28>: movq %r8, -0x30(%rbp) 
    0x10044a1c0 <+32>: movq %r9, -0x38(%rbp) 
    0x10044a1c4 <+36>: movq %rax, -0x40(%rbp) 
    0x10044a1c8 <+40>: movq -0x10(%rbp), %rax 
    0x10044a1cc <+44>: movq -0x38(%rbp), %rdx 
    0x10044a1d0 <+48>: movq 0x2ffda9(%rip), %rsi  ; "handleCookiesForResponse:" 
    0x10044a1d7 <+55>: movq %rax, %rdi 
    0x10044a1da <+58>: callq 0x1005839a2    ; symbol stub for: objc_msgSend 

,然後轉到指令objc_msgSend

libobjc.A.dylib`objc_msgSend: 
-> 0x7fff9084a0c0 <+0>: testq %rdi, %rdi 
    0x7fff9084a0c3 <+3>: je  0x7fff9084a140   ; <+128> 
    0x7fff9084a0c6 <+6>: testb $0x1, %dil 
    0x7fff9084a0ca <+10>: jne 0x7fff9084a14b   ; <+139> 
    0x7fff9084a0cd <+13>: movabsq $0x7ffffffffff8, %r11 
    0x7fff9084a0d7 <+23>: andq (%rdi), %r11 
    0x7fff9084a0da <+26>: movq %rsi, %r10 
    0x7fff9084a0dd <+29>: andl 0x18(%r11), %r10d 

我有時在偏移量+29上崩潰,當CPU試圖取消引用%r11寄存器時。

我的問題是,爲什麼objc_msgSend解除引用註冊?根據System V ABI這是一個臨時寄存器。但它每次被取消引用objc_msgSend,我真的不知道它用於什麼。

我崩潰發生的事情時,有在%r11

無效的指針,看起來像在+23,該%rdi寄存器(指針接收器)取消引用和andq「隨着%r11萬桶,但我不不要做什麼。但是如果接收器在這裏被釋放,%r11可能會被垃圾填滿?

這一理論得到這個assembly source w/ comments

在哪裏,我認爲它指出了%r11用於isa財產
「級=自我> ISA」證實。

這將意味着該對象被釋放,因爲isa屬性junked

如果是這樣的話,我怎麼能防止呢?

在致電objc_msgSend之前查看if(self)就足夠了嗎?

+0

msgSend所做的第一件事就是如果在調用之前這樣做並不會有多大幫助。正如你所說,'self'指向垃圾,但不幸的是它不是'NULL'。 – Jester

+0

有什麼辦法來檢查'self'的地址是否包含有效的對象,而不是垃圾? –

回答

4

不幸的是,您鏈接的網站已過時。它沒有解釋你正在使用的objc_msgSend的確切版本。

爲了理解反彙編器的輸出,你需要了解的是Objective-C運行時現在有一個叫做「非指針isa」的特性。 Another page on that site解釋非指針isa,但我會總結。

歷史上,對象的isa字段是指向對象類的指針。這個指針不需要完整的64位,因爲Apple的操作系統都不使用完整的64位地址空間。該類地址的許多位始終爲零。

而不是浪費每個對象中的所有位,非指針isa使用其他的東西,如存儲對象的引用計數。這意味着當你需要指向類的指針時,你需要將這些其他位設回零以獲得有效地址。計算isa & 0x7ffffffffff8關閉(屏蔽掉)所有的非指針位,所以你得到一個有效的指針類...

...如果isa字段沒有被破壞。如果isa字段已損壞,則會發生垃圾。如果垃圾是無效地址,則會發生崩潰。

這裏發生了什麼是你覆蓋了包含該對象的內存,使得isa字段不再有效。

要調試問題,請閱讀how to find zombies。如果這沒有幫助,請看this WWDC video about using the address sanitizer

+0

感謝您的徹底答案和鏈接:)問題是,我不能再現這個問題,它通過HockeyApp進來,所以我嚴格從調查崩潰日誌和程序集。你知道我如何覆蓋包含原始接收器對象的內存嗎?我會假定系統能夠防止這種情況發生 - 只在已釋放的內存中寫入內容。 –

+0

在單個過程中沒有類似的保護。 ARC(和Swift)可以幫助您避免內存管理錯誤,但您仍然可以製作它們。我建議您在Address Sanitizer下儘可能多地測試您的應用程序,並查看是否有任何警告。 –

+0

感謝您的鏈接。我觀看了視頻,如果你不介意的話,還有另外一個問題。在25點12分,她談到陰影貼圖。並解釋Address Sanitizer如何工作,在每次訪問內存之前添加一條指令來檢查地址是否「中毒」,如果發現爲真,則** crash **。我的問題是,如果你沒有運行Sanitizer,那麼應用程序不會在無效存儲器訪問時崩潰? –

2

如您所說,此時的%r11是來自selfisa指針。如果self在這一點上是垃圾內存,那麼它的第一個單詞指向垃圾就不足爲奇了。

要清楚,當你說「在調用objc_msgSend之前檢查是否(自我)就足夠了嗎?」我假設你並不是說你自己打電話給objc_msgSend。 (從不這樣做。)在調用此方法之前檢查self對於垃圾是無濟於事的。這是一個非0指針,所以這是真的。 (如果它是0,我們已經通過在objc_msgSend頂部的無消息傳遞保護)。

您已經以某種方式刪除了該內存。也許是過度釋放(儘管我在這種情況下懷疑)。也許你有C數據結構並砸碎你的堆棧(感覺更可能)。也許這個對象正在被另一個線程解除分配?這可能是很多事情。

+0

感謝您的時間^^。這很難調試,因爲我無法複製它,我要從HockeyApp的崩潰日誌中查看,然後在Xcode中查看程序集。您能否詳細說明C數據結構如何粉碎堆棧,以及這意味着什麼?或者幫我讀一個鏈接?這是你在說什麼嗎? http://stackoverflow.com/a/1347464/2415178 –

+0

我說「堆棧粉碎」,當我真的意味着「運行C數據結構,通常是一個數組結束」。考慮到崩潰,它會比堆棧上的堆更可能。看看Xcode的「Malloc Guard邊緣」來幫助找到那種錯誤。 「配置文件」>「運行」>「診斷」中的其他內存管理選項也可能對此有所幫助(請參閱rob mayoff對鏈接的回答)。 –

+0

(順便說一句,你所知道的和不知道的東西對我來說真的很獨特,這表明你在相當先進的水平上學習非常努力,沒有很多背景知識,我印象深刻,但是這使得它有點難以回答,你對ABI和反向工程objc_msgSend有了一個奇怪的認識,但並不知道C存儲管理的普遍適用性,再次,我留下了深刻的印象,但如果我們假設你知道的比你多實際上可能會在錯誤的級別上回答。) –

相關問題