如何找到导致 Objective C 崩溃的函数调用的来源?
How to find the origin of a function call that is leading to crash in Objective C?
我用 Objective C 编写的 iPad 应用程序在框架内编写的 NSDictionary 类别上的方法上崩溃(我在框架中只有头文件)。我没有在任何地方调用该类别方法,但它以某种方式被调用并且它因无法识别的选择器发送到实例而崩溃。我想找到导致这种情况的呼叫的来源。有什么办法可以做到吗?
它仅在 iOS14 上崩溃,在 iOS 以下版本上运行良好。非常感谢任何帮助。
更新了崩溃日志 - NSDictionary(NSDictionary_SA_Additions) 是我之前提到的框架内的类别。
2020-08-27 11:00:03.017073+0100 MyApp[5881:81328] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConstantIntegerNumber characterAtIndex:]: unrecognized selector sent to instance 0x7fff86cc4850'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff20439dee __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177f78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff2044893f +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
3 CoreFoundation 0x00007fff2043e32e ___forwarding___ + 1489
4 CoreFoundation 0x00007fff20440368 _CF_forwarding_prep_0 + 120
5 Foundation 0x00007fff207c2b1f -[NSDictionary(NSKeyValueCoding) valueForKey:] + 79
6 MyApp 0x0000000101b645fd -[NSDictionary(NSDictionary_SA_Additions) SA_md5Hash] + 397
7 MyApp 0x0000000101b64646 -[NSDictionary(NSDictionary_SA_Additions) SA_md5Hash] + 470
8 MyApp 0x0000000101b6445b -[NSDictionary(NSDictionary_SA_Additions) hash] + 43
9 libcache.dylib 0x00007fff53be7bc7 _entry_get_optionally_checking_collisions + 42
10 libcache.dylib 0x00007fff53be6097 cache_get + 128
11 CoreFoundation 0x00007fff20465132 -[NSCache objectForKey:] + 152
12 CoreText 0x00007fff21000ed2 _ZN15TPurgeableCache19RetainedValueForKeyEPKv + 54
13 CoreText 0x00007fff210b192e _ZN12TCGFontCache21CopyFontWithVariationEP6CGFontPK14__CFDictionary + 1694
14 CoreText 0x00007fff210813e4 _ZNK29TTenuousComponentInstanceFont16CopyGraphicsFontEv + 150
15 CoreText 0x00007fff20fdf98b _ZNK9TBaseFont26GetInitializedGraphicsFontEv + 63
16 CoreText 0x00007fff2106ca11 _ZNK9TBaseFont13GetParserFontEv + 9
17 CoreText 0x00007fff21054284 _ZNK10TcmapTable8MapRangeE7CFRangePt + 42
18 CoreText 0x00007fff21072c20 _ZNK9TBaseFont26GetGlyphsForCharacterRangeE7CFRangePt + 94
19 CoreText 0x00007fff2107eab8 _ZNK14TComponentFont26GetGlyphsForCharacterRangeE7CFRangePt + 278
20 CoreText 0x00007fff20fc884a _ZN15TASCIIDataCacheC2EPK5TFont + 78
21 CoreText 0x00007fff20fdd430 _ZNK5TFont18InitASCIIDataCacheEv + 34
22 CoreText 0x00007fff20fcf9d0 CTFontGetLatin1GlyphsAndAdvanceWidths + 51
23 UIFoundation 0x00007fff239e0268 -[NSCoreTypesetter _NSFastDrawString:length:attributes:paragraphStyle:typesetterBehavior:lineBreakMode:rect:padding:graphicsContext:baselineRendering:usesFontLeading:usesScreenFont:scrollable:syncAlignment:mirrored:boundingRectPointer:baselineOffsetPointer:drawingContext:] + 1821
24 UIFoundation 0x00007fff239e1b0b -[NSCoreTypesetter _stringDrawingCoreTextEngineWithOriginalString:rect:padding:graphicsContext:forceClipping:attributes:stringDrawingOptions:drawingContext:stringDrawingInterface:] + 1278
25 UIFoundation 0x00007fff239db738 __NSStringDrawingEngine + 2887
26 UIFoundation 0x00007fff239dabc7 -[NSString(NSExtendedStringDrawing) boundingRectWithSize:options:attributes:context:] + 187
27 UIKitCore 0x00007fff24ae3d10 -[UILabel _drawTextInRect:baselineCalculationOnly:] + 4020
28 UIKitCore 0x00007fff24ae0ff7 -[UILabel drawTextInRect:] + 1061
29 UIKitCore 0x00007fff24ae3e42 -[UILabel drawRect:] + 71
30 UIKitCore 0x00007fff24ba1c85 -[UIView(CALayerDelegate) drawLayer:inContext:] + 625
31 QuartzCore 0x00007fff27a7830d -[CALayer drawInContext:] + 288
32 QuartzCore 0x00007fff27935321 CABackingStoreUpdate_ + 190
33 QuartzCore 0x00007fff27a819b9 ___ZN2CA5Layer8display_Ev_block_invoke + 53
34 QuartzCore 0x00007fff27a77b4a -[CALayer _display] + 2111
35 QuartzCore 0x00007fff27a8b327 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 463
36 QuartzCore 0x00007fff279cb3d4 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
37 QuartzCore 0x00007fff27a02163 _ZN2CA11Transaction6commitEv + 783
38 UIKitCore 0x00007fff246656a0 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 81
39 CoreFoundation 0x00007fff203a834b __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
40 CoreFoundation 0x00007fff203a775f __CFRunLoopDoBlocks + 434
41 CoreFoundation 0x00007fff203a217c __CFRunLoopRun + 899
42 CoreFoundation 0x00007fff203a190e CFRunLoopRunSpecific + 567
43 GraphicsServices 0x00007fff2ba85db3 GSEventRunModal + 139
44 UIKitCore 0x00007fff24647ffd -[UIApplication _run] + 912
45 UIKitCore 0x00007fff2464cf0e UIApplicationMain + 101
46 MyApp 0x000000010177f16e main + 78
47 libdyld.dylib 0x00007fff20257415 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConstantIntegerNumber characterAtIndex:]: unrecognized selector sent to instance 0x7fff86cc4850'
CoreSimulator 732.13 - Device: iPad Air (3rd generation) (C762993D-AFF7-412A-89AF-92DB600B2153) - Runtime: iOS 14.0 (18A5351d) - DeviceType: iPad Air (3rd generation)
terminating with uncaught exception of type NSException
有意思。似乎基于此 answer CFDictionary
/ NSDictionary
的真正哈希函数是最基本的(计算的哈希值是字典中元素的数量)。如果有人想要使用 NSDictionary
作为键的字典,那将导致很多冲突。使用 SA_md5Hash
实现通过 NSDictionary_SA_Additions
类别覆盖股票哈希函数似乎是一个合理的理由。
我认为下一步是研究 NSDictionary
的 iOS14 哈希函数(内部具有不同的值)与以前的 iOS 版本。
我想如果检测到 运行 iOS14,一个潜在的修复可能是恢复 NSDictionary
的散列函数,前提是麻烦的框架会继续正常工作。
更新:
您无法还原类别。但是你可以通过 swizzling 来覆盖它。
#include <objc/message.h>
__attribute__((constructor))
static void premain() {
SEL hashSelector = @selector(hash);
Method method = class_getClassMethod([NSDictionary class], hashSelector);
const char * encoding = method_getTypeEncoding(method);
IMP newHashImplementation = imp_implementationWithBlock(^NSUInteger (NSDictionary* self, SEL __cmd){
return CFDictionaryGetCount((CFDictionaryRef)self);
});
class_replaceMethod([NSDictionary class], hashSelector, newHashImplementation, encoding);
}
这是继承了原始实现精神的新实现。不幸的是,由于选择器名称("hash"
)冲突,我们无法在类别覆盖后获得真正的原始版本。 __attribute__((constructor))
保证它在您的应用程序完成启动类别后第一时间执行。
或者 要从字面上恢复类别,需要对框架进行二进制修改。具体来说 __TEXT,__objc_methname
您可以将 hash
更改为其他内容,例如 hasg
。但这几乎肯定会违反框架的许可。
有人在 NSConstantIntegerNumber 类型的对象上调用 NSString 函数 characterAtIndex,这显然是行不通的。
除非你觉得有责任以某种方式将整数设置为需要字符串键的字典中的键,否则我会针对 iOS 14.
提交错误报告
我用 Objective C 编写的 iPad 应用程序在框架内编写的 NSDictionary 类别上的方法上崩溃(我在框架中只有头文件)。我没有在任何地方调用该类别方法,但它以某种方式被调用并且它因无法识别的选择器发送到实例而崩溃。我想找到导致这种情况的呼叫的来源。有什么办法可以做到吗?
它仅在 iOS14 上崩溃,在 iOS 以下版本上运行良好。非常感谢任何帮助。
更新了崩溃日志 - NSDictionary(NSDictionary_SA_Additions) 是我之前提到的框架内的类别。
2020-08-27 11:00:03.017073+0100 MyApp[5881:81328] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConstantIntegerNumber characterAtIndex:]: unrecognized selector sent to instance 0x7fff86cc4850'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff20439dee __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff20177f78 objc_exception_throw + 48
2 CoreFoundation 0x00007fff2044893f +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
3 CoreFoundation 0x00007fff2043e32e ___forwarding___ + 1489
4 CoreFoundation 0x00007fff20440368 _CF_forwarding_prep_0 + 120
5 Foundation 0x00007fff207c2b1f -[NSDictionary(NSKeyValueCoding) valueForKey:] + 79
6 MyApp 0x0000000101b645fd -[NSDictionary(NSDictionary_SA_Additions) SA_md5Hash] + 397
7 MyApp 0x0000000101b64646 -[NSDictionary(NSDictionary_SA_Additions) SA_md5Hash] + 470
8 MyApp 0x0000000101b6445b -[NSDictionary(NSDictionary_SA_Additions) hash] + 43
9 libcache.dylib 0x00007fff53be7bc7 _entry_get_optionally_checking_collisions + 42
10 libcache.dylib 0x00007fff53be6097 cache_get + 128
11 CoreFoundation 0x00007fff20465132 -[NSCache objectForKey:] + 152
12 CoreText 0x00007fff21000ed2 _ZN15TPurgeableCache19RetainedValueForKeyEPKv + 54
13 CoreText 0x00007fff210b192e _ZN12TCGFontCache21CopyFontWithVariationEP6CGFontPK14__CFDictionary + 1694
14 CoreText 0x00007fff210813e4 _ZNK29TTenuousComponentInstanceFont16CopyGraphicsFontEv + 150
15 CoreText 0x00007fff20fdf98b _ZNK9TBaseFont26GetInitializedGraphicsFontEv + 63
16 CoreText 0x00007fff2106ca11 _ZNK9TBaseFont13GetParserFontEv + 9
17 CoreText 0x00007fff21054284 _ZNK10TcmapTable8MapRangeE7CFRangePt + 42
18 CoreText 0x00007fff21072c20 _ZNK9TBaseFont26GetGlyphsForCharacterRangeE7CFRangePt + 94
19 CoreText 0x00007fff2107eab8 _ZNK14TComponentFont26GetGlyphsForCharacterRangeE7CFRangePt + 278
20 CoreText 0x00007fff20fc884a _ZN15TASCIIDataCacheC2EPK5TFont + 78
21 CoreText 0x00007fff20fdd430 _ZNK5TFont18InitASCIIDataCacheEv + 34
22 CoreText 0x00007fff20fcf9d0 CTFontGetLatin1GlyphsAndAdvanceWidths + 51
23 UIFoundation 0x00007fff239e0268 -[NSCoreTypesetter _NSFastDrawString:length:attributes:paragraphStyle:typesetterBehavior:lineBreakMode:rect:padding:graphicsContext:baselineRendering:usesFontLeading:usesScreenFont:scrollable:syncAlignment:mirrored:boundingRectPointer:baselineOffsetPointer:drawingContext:] + 1821
24 UIFoundation 0x00007fff239e1b0b -[NSCoreTypesetter _stringDrawingCoreTextEngineWithOriginalString:rect:padding:graphicsContext:forceClipping:attributes:stringDrawingOptions:drawingContext:stringDrawingInterface:] + 1278
25 UIFoundation 0x00007fff239db738 __NSStringDrawingEngine + 2887
26 UIFoundation 0x00007fff239dabc7 -[NSString(NSExtendedStringDrawing) boundingRectWithSize:options:attributes:context:] + 187
27 UIKitCore 0x00007fff24ae3d10 -[UILabel _drawTextInRect:baselineCalculationOnly:] + 4020
28 UIKitCore 0x00007fff24ae0ff7 -[UILabel drawTextInRect:] + 1061
29 UIKitCore 0x00007fff24ae3e42 -[UILabel drawRect:] + 71
30 UIKitCore 0x00007fff24ba1c85 -[UIView(CALayerDelegate) drawLayer:inContext:] + 625
31 QuartzCore 0x00007fff27a7830d -[CALayer drawInContext:] + 288
32 QuartzCore 0x00007fff27935321 CABackingStoreUpdate_ + 190
33 QuartzCore 0x00007fff27a819b9 ___ZN2CA5Layer8display_Ev_block_invoke + 53
34 QuartzCore 0x00007fff27a77b4a -[CALayer _display] + 2111
35 QuartzCore 0x00007fff27a8b327 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 463
36 QuartzCore 0x00007fff279cb3d4 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
37 QuartzCore 0x00007fff27a02163 _ZN2CA11Transaction6commitEv + 783
38 UIKitCore 0x00007fff246656a0 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 81
39 CoreFoundation 0x00007fff203a834b __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
40 CoreFoundation 0x00007fff203a775f __CFRunLoopDoBlocks + 434
41 CoreFoundation 0x00007fff203a217c __CFRunLoopRun + 899
42 CoreFoundation 0x00007fff203a190e CFRunLoopRunSpecific + 567
43 GraphicsServices 0x00007fff2ba85db3 GSEventRunModal + 139
44 UIKitCore 0x00007fff24647ffd -[UIApplication _run] + 912
45 UIKitCore 0x00007fff2464cf0e UIApplicationMain + 101
46 MyApp 0x000000010177f16e main + 78
47 libdyld.dylib 0x00007fff20257415 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConstantIntegerNumber characterAtIndex:]: unrecognized selector sent to instance 0x7fff86cc4850'
CoreSimulator 732.13 - Device: iPad Air (3rd generation) (C762993D-AFF7-412A-89AF-92DB600B2153) - Runtime: iOS 14.0 (18A5351d) - DeviceType: iPad Air (3rd generation)
terminating with uncaught exception of type NSException
有意思。似乎基于此 answer CFDictionary
/ NSDictionary
的真正哈希函数是最基本的(计算的哈希值是字典中元素的数量)。如果有人想要使用 NSDictionary
作为键的字典,那将导致很多冲突。使用 SA_md5Hash
实现通过 NSDictionary_SA_Additions
类别覆盖股票哈希函数似乎是一个合理的理由。
我认为下一步是研究 NSDictionary
的 iOS14 哈希函数(内部具有不同的值)与以前的 iOS 版本。
我想如果检测到 运行 iOS14,一个潜在的修复可能是恢复 NSDictionary
的散列函数,前提是麻烦的框架会继续正常工作。
更新: 您无法还原类别。但是你可以通过 swizzling 来覆盖它。
#include <objc/message.h>
__attribute__((constructor))
static void premain() {
SEL hashSelector = @selector(hash);
Method method = class_getClassMethod([NSDictionary class], hashSelector);
const char * encoding = method_getTypeEncoding(method);
IMP newHashImplementation = imp_implementationWithBlock(^NSUInteger (NSDictionary* self, SEL __cmd){
return CFDictionaryGetCount((CFDictionaryRef)self);
});
class_replaceMethod([NSDictionary class], hashSelector, newHashImplementation, encoding);
}
这是继承了原始实现精神的新实现。不幸的是,由于选择器名称("hash"
)冲突,我们无法在类别覆盖后获得真正的原始版本。 __attribute__((constructor))
保证它在您的应用程序完成启动类别后第一时间执行。
或者 要从字面上恢复类别,需要对框架进行二进制修改。具体来说 __TEXT,__objc_methname
hash
更改为其他内容,例如 hasg
。但这几乎肯定会违反框架的许可。
有人在 NSConstantIntegerNumber 类型的对象上调用 NSString 函数 characterAtIndex,这显然是行不通的。
除非你觉得有责任以某种方式将整数设置为需要字符串键的字典中的键,否则我会针对 iOS 14.
提交错误报告