Reputation: 1394
My iPad app which is written in Objective C is crashing on method that is on NSDictionary Category which is in written inside a framework (I have only header files in the framework). I am not calling that category method anywhere but it somehow gets called and it is crashing with unrecognised selector sent to instance. I would like to find the origin of the call that is made which is leading to this. Is there any way we can do that?
It is crashing only on iOS14 and works fine on below versions of iOS. Any help is much appreciated.
UPDATED WITH CRASH LOG - NSDictionary(NSDictionary_SA_Additions) is category inside a framework which I mentioned earlier.
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
Upvotes: 1
Views: 415
Reputation: 52530
Someone is calling the NSString function characterAtIndex on an object of type NSConstantIntegerNumber, which obviously cannot work.
Unless you feel responsible for somehow setting an integer as a key in a dictionary that expects string keys, I'd file a bug report against iOS 14.
Upvotes: 1
Reputation: 5543
Interesting. It seems based on this answer the genuine hash function of CFDictionary
/ NSDictionary
is as basic as it gets (the computed hash value is number of elements in a dictionary). That would lead to A LOT of collisions if someone wanted to have a dictionary using NSDictionary
as a key. Seems a plausible reason to override the stock hash function through the NSDictionary_SA_Additions
category with the SA_md5Hash
implementation.
I think next step would be to investigate iOS14 hash function of NSDictionary
(with different values inside) vs previous iOS versions.
I imagine a potential fix could be restoring the hash function of NSDictionary
if detected running iOS14 provided the troublesome framework would keep working correctly.
UPDATE: You cannot revert a category. But you can override it through 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);
}
That's a new implementation in spirit of the original one. Unfortunately we cannot get the genuine original one after the category override due to the selector name("hash"
) clash. __attribute__((constructor))
guarantees it's executed as the very 1st thing after your app has completed initiating categories.
Alternatively to revert the category in a literal sense a binary modification of the framework is required. Specifically the __TEXT,__objc_methname
You'd change the hash
to something else e.g hasg
. But that's almost certain to be against the license of the framework.
Upvotes: 1