Paradigm Shift Design

ISHITOYA Kentaro's blog.

EXEC_BAD_ACCESSのデバッグ方法

xcodeでプログラムを書いていると、メモリ管理なぞ忘却のかなたなので、リークしていたり、解放済みのメモリにアクセスしていたりと、問題が多々ある。


xcodeでのデバッグコンソールは、基本的にgdbなので、VisualStudioで開発するようには簡単に問題箇所を見つけ出すことができない。
ポインタに対する不正なアクセスは、大体のところ

プログラムはシグナルを受信しました:“EXC_BAD_ACCESS”

というメッセージが出るだけで、「どこでそれが起こったのか」についての何の手がかりも与えられない。Breakすらしない。


さすがにこんな状況でデバッグしている人はいないだろうと、検索をかけてみると、

あたりが役に立ちそうである。


とりあえず色々試行錯誤してみたが、NSZombieEnabled - CocoaDevの下のほうにある.gdbinitを~/.gdbinitとして保存して実行するも、

# might also be set in launch arguments.
set env NSZombieEnabled=YES
set env NSDeallocateZombies=NO
set env MallocCheckHeapEach=100000
set env MallocCheckHeapStart=100000
set env MallocScribble=YES
set env MallocGuardEdges=YES
set env MallocCheckHeapAbort=1

set env CFZombie 5

fb -[_NSZombie init]
fb -[_NSZombie retainCount]
fb -[_NSZombie retain]
fb -[_NSZombie release]
fb -[_NSZombie autorelease]
fb -[_NSZombie methodSignatureForSelector:]
fb -[_NSZombie respondsToSelector:]
fb -[_NSZombie forwardInvocation:]
fb -[_NSZombie class]
fb -[_NSZombie dealloc]

この一番重要そうなところが利かない。何かやり方があるのだろうけれど、とりあえず、プロジェクト->アクティブな実行可能ファイル->引数と選択して、環境変数のところに、

MallocStackLogging=YES
MallocStackLoggingNoCompat=YES
NSZombieEnabled=YES
NSDebugEnabled=YES

を設定し、gdbを起動すると、mallocのログが記録される。
そして、解放されたポインタにアクセスすると、

2008-10-07 02:05:06.849 TYPOER[1433:20b] *** -[CFString respondsToSelector:]: message sent to deallocated instance 0x4efbc0

のように、先ほどのEXEC_BAD_ACCESSよりは大分ましな出力になる。ここで、PIDとアドレスを使って、

shell malloc_history 1433 0x4efbc0

とgdbで入力を行うと、

Call [2] [arg=32]: thread_a0332fa0 |start | main | UIApplicationMain | -[UIApplication _run] | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CATransactionCommit | CAContextCommitTransaction | CALayerLayoutIfNeeded | -[CALayer layoutSublayers] | -[UILayoutContainerView layoutSubviews] | -[UINavigationController viewWillLayoutSubviews] | -[UINavigationController _startTransition:fromViewController:toViewController:] | -[IndexViewController viewWillAppear:] | -[IndexViewController refresh] | +[BRService list:] | -[NSString(NSString_SBJSON) JSONValue] | -[SBJSON objectWithString:error:] | -[SBJSON objectWithString:allowScalar:error:] | -[SBJSON scanRestOfArray:error:] | -[SBJSON scanRestOfDictionary:error:] | -[SBJSON scanRestOfArray:error:] | -[SBJSON scanRestOfDictionary:error:] | -[SBJSON scanRestOfString:error:] | +[NSMutableString stringWithCapacity:] | -[NSPlaceholderMutableString initWithCapacity:] | CFStringCreateMutable | _CFRuntimeCreateInstance | malloc_zone_malloc

のようなログが表示される。
これでわかるのは、BAD_ACCESSなポインタがどこでmallocされたのかということで、それであたりをつけて行く。


というわけで、

プログラムはシグナルを受信しました:“EXC_BAD_ACCESS”

よりはましな情報を取得できたが、「どこでエラーが起きたのか」がわかるようにするためには、もう少し調査が必要だろう。


きっと、この文章はNDAに違反していないッ。
iphoneとか書いてないし。
…微妙だな。


せんでん

1タップで写真共有tottepost
カメラのついたiPad/iPhoneで撮った写真を、その場でFacebook/Mixi/DropboxなどのサービスにアップロードできるtottepostというiOSアプリを開発しています!詳しくは、iTunes App Storeをご覧ください。


ご購入はこちら!
1タップで写真共有 - tottepost - ISHITOYA Kentaro