2016-05-25 13 views
0

Was passiert, wenn method_setImplementation() die Methode dealloc der NSObject-Klasse ersetzt und gleichzeitig in einem anderen Thread eine NSObject-Instanz aufruft oder kurz davor ist, die Methode dealloc aufzurufen.ist method_setImplementation() atomar?

Erhält die Instanz die richtige Adresse dealloc Methode? Ich habe einen zufälligen Absturz, wenn ich Methode Swizzling.And es ist immer abgestürzt, wenn es Dealloc-Methode aufruft.

Hier ist mein Absturz Info:

Exception Type: EXC_BAD_ACCESS (SIGBUS) 
Exception Codes: 0x00000000 at 0x0000000000000000 

und abgestürzt thread:

Thread 0: 
0 libsystem_kernel.dylib   0x00000001837b7ffc 0x18379c000 + 114684 (__psynch_rw_unlock + 8) 
1 libsystem_pthread.dylib   0x0000000183881b1c 0x183880000 + 6940 (pthread_rwlock_unlock + 380) 
2 libobjc.A.dylib     0x000000018328f718 0x18327c000 + 79640 (<redacted> + 20) 
3 libobjc.A.dylib     0x00000001832894a0 0x18327c000 + 54432 (method_setImplementation + 64) 
4 MyApp       0x0000000100904824 0x1000b4000 + 8718372 (kszombie_install + 204) 
5 MyApp       0x0000000100448248 0x1000b4000 + 3752520 (-[DYCrashReportManager configureAdvancedSettings] + 60) 
6 MyApp       0x000000010044756c 0x1000b4000 + 3749228 (+[DYCrashReportManager setDefaultKSCrashHander] + 100) 
7 MyApp       0x00000001000e15b4 0x1000b4000 + 185780 (-[AppDelegate application:didFinishLaunchingWithOptions:] + 700) 
8 UIKit       0x0000000188dde8a8 0x188d54000 + 567464 (<redacted> + 400) 
9 UIKit       0x000000018900e094 0x188d54000 + 2859156 (<redacted> + 2904) 
10 UIKit       0x0000000189012500 0x188d54000 + 2876672 (<redacted> + 1684) 
11 UIKit       0x000000018900f674 0x188d54000 + 2864756 (<redacted> + 168) 
12 FrontBoardServices    0x00000001855bf7ac 0x185598000 + 161708 (<redacted> + 36) 
13 FrontBoardServices    0x00000001855bf618 0x185598000 + 161304 (<redacted> + 168) 
14 FrontBoardServices    0x00000001855bf9c8 0x185598000 + 162248 (<redacted> + 56) 
15 CoreFoundation     0x0000000183bd5124 0x183af4000 + 921892 (<redacted> + 24) 
16 CoreFoundation     0x0000000183bd4bb8 0x183af4000 + 920504 (<redacted> + 540) 
17 CoreFoundation     0x0000000183bd28b8 0x183af4000 + 911544 (<redacted> + 724) 
18 CoreFoundation     0x0000000183afcd10 0x183af4000 + 36112 (CFRunLoopRunSpecific + 384) 
19 UIKit       0x0000000188dd7834 0x188d54000 + 538676 (<redacted> + 460) 
20 UIKit       0x0000000188dd1f70 0x188d54000 + 515952 (UIApplicationMain + 204) 
21 DuoYiIM       0x00000001000c4300 0x1000b4000 + 66304 (main + 132) 
22 libdyld.dylib     0x000000018369a8b8 0x183698000 + 10424 (<redacted> + 4) 

Thread 2 Crashed: 
0 (null) 0x0000000000000000 0x0 + 0 
1 CoreFoundation     0x0000000183b01f14 0x183af4000 + 57108 (<redacted> + 148) 
2 libobjc.A.dylib     0x000000018329dae8 0x18327c000 + 137960 (<redacted> + 508) 
3 Foundation      0x00000001846dc844 0x184500000 + 1951812 (<redacted> + 1028) 
4 libxpc.dylib     0x00000001838b4b4c 0x1838b0000 + 19276 (<redacted> + 28) 
5 libxpc.dylib     0x00000001838b4af0 0x1838b0000 + 19184 (<redacted> + 40) 
6 libdispatch.dylib    0x000000018366947c 0x183668000 + 5244 (<redacted> + 16) 
7 libdispatch.dylib    0x00000001836754c0 0x183668000 + 54464 (<redacted> + 864) 
8 libdispatch.dylib    0x000000018366cf80 0x183668000 + 20352 (<redacted> + 464) 
9 libdispatch.dylib    0x000000018366947c 0x183668000 + 5244 (<redacted> + 16) 
10 libdispatch.dylib    0x0000000183677914 0x183668000 + 63764 (<redacted> + 2140) 
11 libdispatch.dylib    0x00000001836770b0 0x183668000 + 61616 (<redacted> + 112) 
12 libsystem_pthread.dylib   0x0000000183881470 0x183880000 + 5232 (_pthread_wqthread + 1092) 

Ich bekam einen Null-Zeiger.

Gibt es eine sichere Methode, die Dealloc-Methode zu ersetzen?

+1

Informationen in Ihrem Stack-Trace über Symbole in libobjc.dylib zu redigieren ist überhaupt nicht nützlich. Es gibt absolut keine Möglichkeit, diese Adressen in etwas Nützliches zu symbolisieren. –

+0

@ Richard J. Ross III.Ich benutze KSCrash, um meinen Absturzbericht zu bekommen.Und ich finde jedes Mal, wenn es abgestürzt ist, gibt es eine Dealloc-Zeichenfolge in x1 register.Das bedeutet, dass das System dealloc-Methode aufgerufen hat.Das Problem muss von sein Methode Swizzling, aber ich weiß nicht den genauen Grund.Ich bezweifle nur, vielleicht method_setImplementation() ist nicht atomar, also kam ich um Hilfe. – zuik

Antwort

2

Die Objc-Laufzeitmanipulationsmethoden sind im Allgemeinen atomar, aber Atomarität bedeutet nicht threadsicher. Thread Ein Verschrauben mit der Implementierung eines Objekts, während Thread B dieses Objekt verwendet, ist immer gefährlich, einfach weil es keine Garantie gibt, ob Thread B die neue oder alte Implementierung verwenden wird.

Insgesamt aber Swizzling Methoden schlecht ist und NSObject Methoden Swizzling ist schlimmer.

+0

Ist swizzling Dealloc sogar gut unter ARC definiert? Ich dachte, der Compiler würde das meiste davon optimieren, wenn die Klasse es nicht direkt definiert. –

+1

@RobNapier Yup; Ich vermute, dass man mit dealloc über swizzling mucken kann, ist wahrscheinlich das Loch tiefer unter ARC zu graben, aber ich denke nicht, dass es flach gebrochen ist. I.e. Da grundsätzlich jede Methode aus modulübergreifenden Grenzen aufgerufen werden kann, muss ARC immer mit Nicht-ARC kompatibel sein und umgekehrt. – bbum

0

Ich denke, ich finde den Grund meines Absturzes. Das liegt daran, dass KSCrash die Methode dealloc swizzled, um Zombie-Objekte zu erkennen.

static IMP g_originalDealloc_NSObject; 
static void handleDealloc_NSObject(id self, SEL _cmd) 
{ 
    handleDealloc(self); 
    typedef void (*fn)(id,SEL); 
    fn f = (fn)g_originalDealloc_NSObject; 
    f(self, _cmd); 
} 
static void installDealloc_NSObject() 
{ 
    g_originalDealloc_NSObject = method_setImplementation(class_getInstanceMethod([NSObject class], @selector(dealloc)),(IMP)handleDealloc_NSObject); 
} 

Der Absturz passiert ist, als in installDealloc_NSObject(), method_setImplementation() die Umsetzung tat ändern, hatte aber nicht die alte Implementierung g_originalDealloc_NSObject yet.And im selben Moment in einem anderen Thread zurückkehren, aufgerufen ein Objekt dealloc, so in handleDealloc_NSObject() es habe einen Nullzeigerfehler bekommen.