Unexpected EXC_BAD_ACCESS while setting weak property at BG global queue - ios

In my ChatMessage class I have the weak reference to Chat class
#interface ChatMessage : NSObject
#property (nonatomic, weak) Chat *chat;
I make the following initialization within Chat implementation on the global queue
ChatMessage *chatMessage = [[ChatMessage alloc] initWithDictionary:dictionary];
chatMessage.chat = self;
and get very strange error at the second line
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x4c008be5
Triggered by Thread: 17
Thread 17 Crashed:
0 libobjc.A.dylib 0x39f535d2 cache_getImp + 18
1 libobjc.A.dylib 0x39f4e9a8 lookUpImpOrForward + 28
2 libobjc.A.dylib 0x39f4e942 lookUpImpOrNil + 22
3 libobjc.A.dylib 0x39f48aca class_getMethodImplementation + 30
4 libobjc.A.dylib 0x39f5833a weak_register_no_lock + 38
5 libobjc.A.dylib 0x39f586fa objc_storeWeak + 106
6 MyMessenger 0x000d366c -[ChatMessage setChat:]
7 MyMessenger 0x001173bc -[Chat getMessagesForPage:]
8 libdispatch.dylib 0x3a432d50 _dispatch_call_block_and_release + 8
9 libdispatch.dylib 0x3a438684 _dispatch_root_queue_drain + 224
10 libdispatch.dylib 0x3a4388d8 _dispatch_worker_thread2 + 52
11 libsystem_pthread.dylib 0x3a563c14 _pthread_wqthread + 296
12 libsystem_pthread.dylib 0x3a563ad8 start_wqthread + 4
Did someone come across such problems with setting weak properties?

It appears that the problem is in simultaneous access to this weak property from different threads.
Weakness of the property doesn't allow us to neglect multithread assigning.
The safe rule to work with datasources is to change it synchronously within one selected thread.

Related

Crash llibobjc.A.dylib objc_release + 36

I use crashlytics to get the crashes of my app, i am currently Crashlytics version: 3.9.3. Some users are getting a crash that I cannot seem to repro on my machine. This is the logs from Fabric:
Crashed: com.apple.root.default-qos
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x00004a4b9a43bec8
#37. Crashed: com.apple.root.default-qos
0 libobjc.A.dylib 0x7fff6b43d184 objc_release + 36
1 MyApp 0x10805ad2d __66-[AppManager getCountriesDelegate:]_block_invoke (AppManager.m:1412)
2 libdispatch.dylib 0x7fff6c006591 _dispatch_call_block_and_release + 12
3 libdispatch.dylib 0x7fff6bffed50 _dispatch_client_callout + 8
4 libdispatch.dylib 0x7fff6c00bc61 _dispatch_queue_override_invoke + 880
5 libdispatch.dylib 0x7fff6c000941 _dispatch_root_queue_drain + 515
6 libdispatch.dylib 0x7fff6c0006ed _dispatch_worker_thread3 + 101
7 libsystem_pthread.dylib 0x7fff6c2c31ca _pthread_wqthread + 1387
8 libsystem_pthread.dylib 0x7fff6c2c2c4d start_wqthread + 13
- (void) getCountriesDelegate:(id<AppManagerDelegate>)delegate
{
__weak __typeof(id<AppManagerDelegate>) weakDelegate = delegate;
__weak __typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //my function definition
});
There are multiples reasons why you can get a EXC_BAD_ACCESS KERN_INVALID_ADDRESS error code. Appel's documentation says:
EXC_BAD_ACCESS/KERN_INVALID_ADDRESS — This is caused by the thread
accessing unmapped memory. It may be triggered by either a data access
or an instruction fetch; the Thread State section describes how to
tell the difference.
You should look deeply at your class AppManager. As the crashlog said's the crash occurs at line 1412 of file AppManager.m in the method getCountriesWithRespectToPurposeAndFavoriteDelegate:.

ios exception analyse NSInternalInconsistencyException

My app crash with a NSInternalInconsistencyException like this
Exception reason:NSInternalInconsistencyException
Exception name:Can't cancel on a touch that isn't already active!
Exception stack:(
0 CoreFoundation 0x0000000191a4d1d0 <redacted> + 148
1 libobjc.A.dylib 0x000000019048455c objc_exception_throw + 56
2 CoreFoundation 0x0000000191a4d08c <redacted> + 0
3 Foundation 0x000000019250502c <redacted> + 112
4 UIKit 0x0000000197fd1960 <redacted> + 404
5 UIKit 0x0000000197fcf970 <redacted> + 1648
6 libdispatch.dylib 0x00000001908d61fc <redacted> + 24
7 libdispatch.dylib 0x00000001908d61bc <redacted> + 16
8 libdispatch.dylib 0x00000001908e43dc <redacted> + 928
9 libdispatch.dylib 0x00000001908d99a4 <redacted> + 652
10 libdispatch.dylib 0x00000001908e634c <redacted> + 572
11 libdispatch.dylib 0x00000001908e60ac <redacted> + 124
12 libsystem_pthread.dylib 0x0000000190adf2a0 _pthread_wqthread + 1288
13 libsystem_pthread.dylib 0x0000000190aded8c start_wqthread + 4
)
How do i analyse the log? Like What do those number tags mean,"+ 148" "+ 56"...? How to detect the code that have invoked this exception.
Is this a crash from a release build of the app, or do you have it in Xcode? If in Xcode please provide the code causing the crash?
Looking at your report, the line
Can't cancel on a touch that isn't already active!
seems very telling. I would look through your code for anywhere you are interacting with a UITouch object, or perhaps a UIGestureRecognizer. My guess would be that somewhere you are manually calling to cancel an interaction that you should not be, and there is a race condition where that can sometimes happen after the system has already cancelled the touch (or vice versa, I guess).

iOS app sometimes crashes when dereferencing weak reference

I have a very simple class:
#interface WORef : NSObject
#property(nonatomic,weak) NSObject * object;
#end
Instances are stored in an NSArray and from time to time (only on the main thread) this array is iterated and I access the "object" property.
All works fine when testing or debugging, but in the production version of my app on the store I sometimes get crash reports when dereferencing the "object" property (the stack trace actually shows the line number of the property definition).
Here is an example of such a call stack:
Thread : Crashed: com.apple.main-thread
0 libsystem_platform.dylib 0x35180518 _os_lock_recursive_abort + 18446744073709552000
1 libsystem_platform.dylib 0x3518050f _os_lock_handoff_lock_slow + 90
2 libobjc.A.dylib 0x34adac3f objc_object::sidetable_release_slow((anonymous namespace)::SideTable*, bool) + 22
3 libobjc.A.dylib 0x34adad2f objc_object::sidetable_release(bool) + 118
4 Foundation 0x27f56f01 -[NSOperationQueue dealloc] + 72
5 libobjc.A.dylib 0x34adad5f objc_object::sidetable_release(bool) + 166
6 libobjc.A.dylib 0x34ac14d9 _class_initialize + 536
7 libobjc.A.dylib 0x34ac705f lookUpImpOrForward + 254
8 libobjc.A.dylib 0x34ac6f1b lookUpImpOrNil + 26
9 libobjc.A.dylib 0x34abfab3 class_getMethodImplementation + 34
10 libobjc.A.dylib 0x34ada583 weak_read_no_lock + 58
11 libobjc.A.dylib 0x34ada871 objc_loadWeakRetained + 92
12 MyApp 0x000c5983 -[WORef object] (WeakRef.m:12)
Anyone know what might be causing this?
// consider this method
-(void)populateArray {
WORef *ref = [WORef new];
ref.object = [YourObject new];
return #[ref];
// once you get out of this scope, the memory space occupied by [YourObject new]
// can be re-allocate to something else and your ref.object would still point at
// that memory space. You would get random crashes depending on when this memory space get re-allocated.
// The reason being is that ref.object hold a weak reference to [YourObject new]
// so it reference count doesn't get incremented.
// Change your property declaration to (nonatomic,strong) instead
}

Core Data EXC_BAD_ACCESS KERN_PROTECTION_FAILURE

I have multiple crash reports that point to the following:
Thread : Crashed: NSOperationQueue 0x18c7fba0
0 libsystem_platform.dylib 0x38665a36 OSAtomicCompareAndSwap32Barrier + 13
1 libobjc.A.dylib 0x3805694b realizeClass(objc_class*) + 78
2 libobjc.A.dylib 0x38058797 lookUpImpOrForward + 74
3 libobjc.A.dylib 0x3805102b _class_lookupMethodAndLoadCache3 + 34
4 libobjc.A.dylib 0x38050df9 _objc_msgSend_uncached + 24
5 CoreData 0x2da7b5bb -[_NSFaultingMutableSet copyWithZone:] + 238
6 MyApp 0x0027226f -[Zoo getSortedCats] (Zoo.m:63)
7 MyApp 0x00286955 -[BlockExecutionOperation main] (BlockExecutionOperation.m:30)
8 Foundation 0x2e627aa5 -[__NSOperationInternal _start:] + 772
9 Foundation 0x2e6cb96d __NSOQSchedule_f + 60
10 libdispatch.dylib 0x3853e4b7 _dispatch_async_redirect_invoke + 110
11 libdispatch.dylib 0x3853f7d9 _dispatch_root_queue_drain + 224
12 libdispatch.dylib 0x3853f9c5 _dispatch_worker_thread2 + 56
13 libsystem_pthread.dylib 0x38669dff _pthread_wqthread + 298
The getSortedCats method looks like this:
- (NSArray *)getSortedCats {
NSSet* cats = [self.cats copy]; //this is line 63, where the crash occurs
//do some sorting
return sortedCats;
}
And Zoo is an NSManagedObject subclass with a cats property:
#property (atomic, retain) NSSet *cats;
So why the crash on the self.cats line? What does this error mean? How to avoid? It only happens once in a while, and is not reproducible.
Peculiarity with Core Data. Sending copy would just return another NSFaultingMutableSet, and Core Data is too buggy to do that right.
Replace it with [NSSet setWithSet:self.cats] and you'd face lesser errors.

Can i make an Xcode breakpoint when a certain class gets added to autorelease pool?

I'm trying to debug some ARC code, and it'd be really helpful if i could find out when an object of a certain class is added to the autorelease pool (not when it is actually autoreleased down the track).
Is this possible, eg with a breakpoint? Or by overwriting the 'autorelease' method and putting a breakpoint in it? Any suggestions?
-- edit --
The problem is that i've got an infrequent crash occurring where a custom subclass of UIView is autoreleased on a background thread, which crashes because UIView's cannot be dealloc'd on a background thread. The trace looks like below:
0 libsystem_kernel.dylib __pthread_kill + 8
1 libsystem_c.dylib pthread_kill + 54
2 libsystem_c.dylib abort + 94
3 libc++abi.dylib abort_message + 46
4 libc++abi.dylib default_terminate() + 24
5 libobjc.A.dylib _objc_terminate + 146
6 libc++abi.dylib safe_handler_caller(void (*)()) + 76
7 libc++abi.dylib operator delete(void*)
8 libc++abi.dylib __cxa_throw + 122
9 libobjc.A.dylib objc_exception_throw + 94
10 CoreFoundation +[NSException raise:format:]
11 Foundation -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 90
12 MYAPP MySuperclass.m line 156 -[MySuperclass dealloc]
13 MYAPP MyClass.m line 41 -[MyClass dealloc]
14 ... libobjc.A.dylib _objc_rootRelease + 36
15 libobjc.A.dylib objc_release + 38
16 libobjc.A.dylib (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 224
17 libobjc.A.dylib _objc_autoreleasePoolPop + 12
18 CoreFoundation _CFAutoreleasePoolPop + 18
19 libdispatch.dylib _dispatch_worker_thread2 + 338
20 libsystem_c.dylib _pthread_wqthread + 294
This might not help with your problem, but I think it answers your original question:
You can add a symbolic breakpoint on [NSObject autorelease] and then set a condition to match your class. If your running on a device $r0 should hold the pointer to the receiving object. You need to do some casting to make the condition work: (BOOL)[(id)$r0 isKindOfClass:[NSArray class]] breaks whenever an NSArray is added to the autoreleasepool. Note that everything will be running very slow as the debugger has to break on every autorelease and check the condition.

Resources