Debugging Magic in Cococa

written by Martin Häcker on

Erstaunlich aber wahr - viele Programmierer scheinen die Debugging-Möglichkeiten der Plattform ihrer Wahl nicht zu kennen.

Cocoa zum Beispiel. Viele Programmierer wissen nicht wie man Speicherlöcher effektiv fängt.

Well, nicht Leaks - da kann man ja mit ObjectAlloc draufhauen und dann das Programm fixen.

Nein, viel problematischer als das sind die doppelten Befreiungen.

id foo = [[NSString alloc] initWithFormat:@"foo"];
[foo release];
// do something else
NSLog(@"foo is %d", [foo length]); // almost certainly bombs

Die krachen nämlich fast immer - und dann sucht man sich tot was genau da eigentlich gekracht hat und woher das genau kommt. Tja.

Dabei kriegt man aus dem Programm eigentlich alle Informationen heraus die man braucht. Man muss nur jedes malloc mitzählen und aufschreiben wo es passiert ist, dann jedes objekt das freigegeben wird, nicht wirklich freigeben, sondern lediglich markieren und dann bei einem weiteren Zugriff auf so ein Objekt eine Exception werfen.

Nichts leichter als das. :)

Man setze diese Environment Variablen (am besten auf einem Duplikat der zu entwanzenden Applikation in Xcode)

MallocStackLogging YES
MallocStackLoggingNoCompact YES
NSZombieEnabled YES
NSDebugEnabled YES

Hat man dass macht die Runtime alles richtig. Jede allokation wird aufgezeichnet und jedes freigegebene Objekt durch einen Zombie ersetzt. Und der Meldet sich, sobald er für irgend etwas verwendet wird. Nämlich so:

2008-08-26 00:19:43.524 CrashTest[1663:817] *** -[CFString length]:
    message sent to deallocated instance 0x105440

Hängt man dann im Debugger, kann man von dort aus direkt diese Information abgreifen.

(gdb) shell malloc_history 1663 0x105440

Call [2] [arg=16]: thread_a00ddfa0 |start | main | -[NSString initWithFormat:] |
 -[NSPlaceholderString initWithFormat:locale:arguments:] |
 _CFStringCreateWithFormatAndArgumentsAux | CFStringCreateCopy |
 __CFStringCreateImmutableFunnel3 | _CFRuntimeCreateInstance | malloc_zone_malloc

Die Syntax für malloc_history ist dabei malloc_history pid address.

Jetzt weiß man mit was für einem Objekt man es zu tun hat und man weiß wo es her kommt.

Nice! (Mehr unter Mac OS X Debugging Magic)

p.s.: Ohne etwas Schelte an Apple geht es aber nicht. Das man sich da von Hand die Umgebungsvariablen einstellen muss - böse. Zumal das noch an einer Custom Executable geschieht. Die sind nämlich nicht im Projektfile gespeichert, sondern in den Dateien die Xcode pro Benutzer anlegt. Das hat zur Folge, dass im Normalfall nicht ein Entwickler diese Dinge raussucht und dann alle anderen im Projekt dass als Tool nutzen können, sondern dass sich das jeder Selber einrichten und warten muss. Ach ja, und natürlich zeichnet malloc_history nur die allocs auf und nicht die frees - das wäre nämlich noch praktischer, dann könnte man nämlich direkt kucken wo es das erste mal freigegeben wurde. Aber nein....