method_setImplementation() 是原子的吗?
is method_setImplementation() atomic?
如果 method_setImplementation()
正在替换 NSObject class 的 dealloc
方法,同时在另一个线程中,一个 NSObject 实例正在调用或即将调用 dealloc
方法。
实例会得到dealloc
方法的正确地址吗?
我在使用方法时随机崩溃 swizzling.And 它总是在调用 dealloc 方法时崩溃。
这是我的崩溃信息:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x00000000 at 0x0000000000000000
和崩溃的线程:
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)
我得到一个空指针。
是否有安全的方法来替换 dealloc 方法?
objc的运行时操作方法一般是原子的,但是原子性并不代表线程安全。线程 A 在线程 B 使用该对象时乱搞对象的实现总是很危险的,因为不能保证线程 B 会使用新的还是旧的实现。
总体而言,调配方法很糟糕,调配 NSObject 的方法更糟。
我想我找到了崩溃的原因。
那是因为 KSCrash 调配了 dealloc
检测僵尸对象的方法。
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);
}
崩溃发生在 installDealloc_NSObject()
,method_setImplementation()
确实更改了实现,但没有 return 旧实现到 g_originalDealloc_NSObject
yet.And在另一个线程中的同一时刻,调用了一个对象 dealloc
,因此在 handleDealloc_NSObject()
中它得到了一个空指针错误。
如果 method_setImplementation()
正在替换 NSObject class 的 dealloc
方法,同时在另一个线程中,一个 NSObject 实例正在调用或即将调用 dealloc
方法。
实例会得到dealloc
方法的正确地址吗?
我在使用方法时随机崩溃 swizzling.And 它总是在调用 dealloc 方法时崩溃。
这是我的崩溃信息:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x00000000 at 0x0000000000000000
和崩溃的线程:
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)
我得到一个空指针。
是否有安全的方法来替换 dealloc 方法?
objc的运行时操作方法一般是原子的,但是原子性并不代表线程安全。线程 A 在线程 B 使用该对象时乱搞对象的实现总是很危险的,因为不能保证线程 B 会使用新的还是旧的实现。
总体而言,调配方法很糟糕,调配 NSObject 的方法更糟。
我想我找到了崩溃的原因。
那是因为 KSCrash 调配了 dealloc
检测僵尸对象的方法。
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);
}
崩溃发生在 installDealloc_NSObject()
,method_setImplementation()
确实更改了实现,但没有 return 旧实现到 g_originalDealloc_NSObject
yet.And在另一个线程中的同一时刻,调用了一个对象 dealloc
,因此在 handleDealloc_NSObject()
中它得到了一个空指针错误。