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とか書いてないし。
…微妙だな。