3

私のAndroidアプリのネイティブ部分でセグメンテーションフォールトが発生しています。その瞬間、void関数が呼び出し元に戻ります。視覚化を改善するために、呼び出し先関数の最後にログステートメントを配置し、呼び出し先への呼び出しの直後に呼び出し元関数にログステートメントを配置します(しゃれでごめんなさい)。logcatでは、最初のメッセージが出力され、2番目のメッセージは出力されません(アプリがクラッシュします)。

メモリの破損の可能性を考えて、mallocデバッグをアクティブ化することにしました(adbシェルで「setproplibc.debug.malloc10」を指定します)。次に、呼び出し先関数の最後からのログメッセージの直後にlogcatでこれを取得します。

D/MyApp - NativeSide(12778):  I am the callee function and I am about to return!
E/libc    (12778): *** FREE CHECK: buffer 0x82869900 corrupted 16 bytes before allocation
E/libc    (12778): call stack:
E/libc    (12778):  0: 8000e3ea
E/libc    (12778):  1: 8000e49c
E/libc    (12778):  2: 8000e4e2
E/libc    (12778):  3: 8000e540
E/libc    (12778):  4: afd14ccc
E/libc    (12778):  5: 81258188
E/libc    (12778):  6: 81258188
E/libc    (12778):  7: 81258188
E/libc    (12778):  8: 81258188
E/libc    (12778):  9: 81258188
E/libc    (12778): 10: 81258188
E/libc    (12778): 11: 81258188
E/libc    (12778): 12: 81258188
E/libc    (12778): 13: 81258188
E/libc    (12778): 14: 81258188
E/libc    (12778): 15: 81258188
E/libc    (12778): 16: 81258188
E/libc    (12778): 17: 81258188
E/libc    (12778): 18: 81258188
E/libc    (12778): 19: 81258188

この出力を解読する方法についての情報が見つかりませんでした。各行に表示される数値は、アプリが起動するたびに変化します。コードからは見つからないので、この情報を破損が発生した場所の手がかりとして使用する方法があることを願っています。また、「-fstack-checkフラグ」を使用してネイティブライブラリを構築しようとしましたが、ログにさらに情報が含まれているかどうか(そうではないようですが、見逃している可能性があります)、または他のことを行う必要があるかどうかはわかりませんでした。それらを取得します。

また、「FREECHECK:」メッセージの後にあるスタックダンプもあります。

I/DEBUG   (12311): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG   (12311): Build fingerprint: 'google/soju/crespo:2.3/GRH55/79397:user/release-keys'
I/DEBUG   (12311): pid: 12778, tid: 12907  >>> com.ntrack.tuner <<<
I/DEBUG   (12311): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad
I/DEBUG   (12311):  r0 deadbaad  r1 45ea374c  r2 00000027  r3 00000000
I/DEBUG   (12311):  r4 00000080  r5 45ea374c  r6 8003422e  r7 45ea37b4
I/DEBUG   (12311):  r8 45da4000  r9 a811eca5  10 00100000  fp 00000001
I/DEBUG   (12311):  ip ffffffff  sp 45ea3738  lr 8000f623  pc 8000f650  cpsr 20000030
I/DEBUG   (12311):  d0  3f9664f48406d639  d1  3f8226e3e96e8495
I/DEBUG   (12311):  d2  3faba1ba1bb34201  d3  0000000000000000
I/DEBUG   (12311):  d4  3d7943379e56fd24  d5  3d8f940585cd5f95
I/DEBUG   (12311):  d6  3f2cf2145b888497  d7  3f2cf214636d85f8
I/DEBUG   (12311):  d8  0000000000000000  d9  0000000000000000
I/DEBUG   (12311):  d10 0000000000000000  d11 0000000000000000
I/DEBUG   (12311):  d12 0000000000000000  d13 0000000000000000
I/DEBUG   (12311):  d14 0000000000000000  d15 0000000000000000
I/DEBUG   (12311):  scr 20000010
I/DEBUG   (12311):

何でも、チェックする典型的な事柄に関する提案、またはmallocデバッグ情報を利用する方法は、非常に役立ちます。ありがとうございます。

4

2 に答える 2

11

malloc デバッグ プロパティは、割り当てた領域の前後にマジック ナンバーを設定している可能性があります。次に、解放するときに、それらの領域をチェックして、マジック ナンバーがまだそこにあることを確認します。

たとえば、1024 バイトを割り当てる場合:

char * p = malloc(1024);

malloc デバッグ コードは、実際には、要求した 1024 バイトに加えて、その周りにいくつかの余分なバイトを割り当てます。

[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
^ 0xc0000000    ^ 0xc0000020

次に、ライブラリはこれらの 32 バイトにマジック値を書き込みます。

[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[  0xdeadd00d   |                           | 0xdeadd00d    ]
^ 0xc0000000    ^ 0xc0000020

ライブラリはに戻り0xc0000020p内部的に0xc0000000サイズなどを保存します。その後、関数は割り当てられた領域を何らかの方法で使用します。

memset(p, 0, 1025);

この行が 1024 バイトを超えてコピーされていることに注意してください。これにより、最後の 32 バイトのマジック領域に 0 が書き込まれます (0最後の 32 バイトの に注意してください0xdeadd00d)。

[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[  0xdeadd00d   |  000...             ...00 | 0x0eadd00d    ]
^ 0xc0000000    ^ 0xc0000020  (address)

関数が free を呼び出す場合:

free(p);

ライブラリは、最初と最後の 32 バイトがまだ0xdeadd00d. 関数が最後の 32 バイトを上書きしたため、投稿したようなエラーが出力されます。

これは、malloc デバッグ チェックがどのように機能するかを示す例にすぎません。malloc デバッグが何をチェックし、どのように機能するかを正確に確認したい場合はbionic、Android ソースのディレクトリに移動し、設定したプロパティを検索しますlibc.debug.malloc

呼び出された関数で割り当てられたメモリをどのように使用するかについて、コードを確認してください。割り当てた領域外の領域に書き込みを行っている可能性があります。

于 2012-07-04T18:24:47.373 に答える
3

私には、これ:

私のAndroidアプリのネイティブ部分のセグメンテーション違反、void関数が呼び出し元に戻る瞬間。

スタックの破損 (ヒープの破損以上) を意味します。この関数のスタックに格納されている状態は何ですか? (およびそれが呼び出すすべての関数から..)?

表示されているコール スタック出力は、破損が検出された時点のスタック上の各関数のアドレスである必要があります。ライブラリがロードされたアドレスを知る必要があります.so。(この質問が役立つと思います: How to use addr2line in Android )

スタック ダンプの上部から繰り返されるという事実81258188は、スタックの下部を吹き飛ばした可能性があることも示唆しています (再帰回数が多すぎるため)。コード内の意図的な再帰に気付いていない場合は、ライブラリがロードされた場所を特定し、それをコードにマップし直すことが役立つ場合があります。

于 2012-07-04T18:38:27.177 に答える