2016-12-05 9 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のメソッド

これを呼び出しているんまず最初に(58をオフセット参照)objc_msgSendを呼び出します。その後、objc_msgSendするための指示に行く

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 

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 

となり、%r11レジスタを参照解除しようとすると、オフセット+29がクラッシュすることがあります。

私の質問は、objc_msgSendはその登録を逆参照していますか?スクラッチレジスタであるSystem V ABIによると、しかし、毎回objc_msgSendが参照解除されています。実際に何が使用されているのか分かりません。無効な逆参照されることが23時の​​ようなに見える%r11

内のポインタ、%rdiレジスタ(受信機へのポインタ)とandqがある場合

私のクラッシュが起こっている「%r11とD、私はドン」それが何をするかを得る。しかし、おそらく受信機がここで割り当て解除された場合、%r11は迷惑メールでいっぱいになるでしょうか?

この理論は、私はそれが%r11isaプロパティ
「クラス=自己> ISA」のために使用されていると述べ考えるこのassembly source w/ comments

によって裏付けられています。それが事実だった、どのように私はこれを防御することができればisaプロパティは

を甲斐無しれるので、オブジェクトが解放されていることを意味する

if(self)を確認してからobjc_msgSendに電話するといいですか?

+0

'msgSend'の最初のことは、' if(self) 'です。そうすることは、呼び出しを行う前にやることはあまり役に立ちません。あなたが言うように、 'self'はゴミを指しますが、残念ながら' NULL'ではありません。 – Jester

+0

'self'のアドレスにゴミではなく有効なオブジェクトが含まれているかどうかを調べる方法はありますか? –

答えて

4

残念ながら、あなたがリンクしているサイトは古くなっています。使用しているobjc_msgSendの正確なバージョンについては説明していません。

逆アセンブラの出力を理解するために知っておくべきことは、Objective-Cランタイムに "non-pointer isa"という機能が追加されたことです。 Another page on that siteは非ポインタのisaについて説明しますが、私は要約します。

オブジェクトのisaフィールドは、歴史的にオブジェクトのクラスへのポインタでした。 Appleのオペレーティングシステムのどれも完全な64ビットアドレス空間を使用していないので、このポインタには64ビットは必要ありません。クラスのアドレスのビットの多くは常にゼロです。

オブジェクトのすべてのビットを無駄にする代わりに、ポインタ以外のisaは、オブジェクトの参照カウントの格納など、他のオブジェクトのビットを使用します。これは、クラスへのポインタが必要なときに、有効なアドレスを取得するために他のビットをゼロに戻す必要があることを意味します。 isa & 0x7ffffffffff8は、非ポインタビットをすべてオフにするので、クラスへの有効なポインタを取得します。

... isaフィールドが破損していない場合は...。 isaフィールドが破損している場合は、ゴミを取得します。ゴミが無効な住所の場合は、クラッシュします。

ここでは、isaフィールドが無効になるように、オブジェクトを含むメモリを上書きしています。

問題をデバッグするには、how to find zombiesを参照してください。それでも問題が解決しない場合は、this WWDC video about using the address sanitizerをご覧ください。

+0

徹底的な答えとリンクをありがとう:)問題は私がこの問題を再現することができないということです。それはHockeyAppによってもたらされたので、クラッシュログとアセンブリを見ることから厳密にデバッグします。元のレシーバオブジェクトを含むメモリをどのように上書きすることができるか知っていますか?私は、システムがそれを守ることができるだろうと思っていたでしょう - 解放されたメモリに書き込むだけですか? –

+0

1つのプロセス内にそのような保護はありません。 ARC(およびSwift)はメモリ管理エラーを回避するのに役立ちますが、それでも作成できます。 Address Sanitizerの下でできるだけ多くのアプリをテストし、警告が表示されるかどうかを確認することをおすすめします。 –

+0

リンクをありがとう。私はビデオを見て、あなたが気にしないか別の質問をしました。 25:12-ishで、彼女はShadow Mappingについて話します。 Address Sanitizerがどのように機能するかについては、アドレスが "中毒"であるかどうかを確認するためのすべてのメモリアクセスの前に命令を追加し、真の場合は**クラッシュ**を確認します。私の質問は、あなたがSanitizerを実行していない場合、その無効なメモリアクセスでアプリがクラッシュしないと思いますか? –

2

あなたが言うように、この時点で%r11はselfからのisaポインタです。この時点でselfがガーベージメモリであれば、最初の単語がガーベジを指すことは驚きではありません。

「あなたがobjc_msgSendを呼び出す前に(自己)が十分であるかどうかを確認しますか?私は、あなた自身がobjc_msgSendと呼んでいるわけではないと思います。 (決して実行しないでください)このメソッドを呼び出す前にselfをチェックすることは、ガベージガードの場合は役に立ちません。それは0でないポインタなので、それは本当です。 (0の場合は、すでにobjc_msgSendの最上部にあるnil-messagingを使用しています)

このメモリは何とか破棄しました。たぶん、過剰リリース(このケースでは私は疑うが)。たぶんあなたはCのデータ構造を持っていて、あなたのスタックを壊してしまったかもしれません。オブジェクトが別のスレッドで割り当て解除されている可能性がありますか?それはたくさんのことがあります。

+0

お時間をありがとう^^。私はそれを再現することができないので、これをデバッグするのは難しいです、私はHockeyAppからのクラッシュログを出して、Xcodeでアセンブリを見ています。 Cのデータ構造がどのようにスタックを破ることができるのか、それはどういう意味ですか?または、読むためのリンクを教えてください。あなたが話していることは、このSOスレッドですか? http://stackoverflow.com/a/1347464/2415178 –

+0

私は本当に "Cデータ構造の終わりで実行される、通常は配列"を意味するとき、 "stack smash"と言いました。クラッシュを考えると、スタック上よりもヒープ上にある可能性が高くなります。 Xcodeの "Malloc Guard Edges"を見て、そのような間違いを見つけるのを助けてください。プロファイル>実行>診断の他のメモリ管理オプションもこれに役立ちます(リンクのためのrob mayoffの答えを見てください)。 –

+0

(あなたはあなたが知っているかわからないことは本当に私にとって非常にユニークです。それはあなたが非常に高度なレベルで非常に勉強していることを示唆しています。 ABIの理解とobjc_msgSendのリバースエンジニアリングの奇妙な組み合わせがありますが、Cメモリ管理の一般的な仕組みではありません。また、私は感心しています。実際には、間違ったレベルで答えるかもしれません。) –

関連する問題