AVPlayerPeriodicCaller crash - ios

I’m getting crash, and I can’t figure out what is causing it. Here what I’m getting from crash report:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000c
Triggered by Thread: 0
Thread 0 Crashed:
0 AVFoundation 0x2f271946 -[AVPlayerPeriodicCaller _effectiveRateChanged] + 418
1 AVFoundation 0x2f270fc8 __43-[AVPlayerTimelyCaller _timebaseDidChange:]_block_invoke + 232
2 libdispatch.dylib 0x3b04ed50 _dispatch_call_block_and_release + 8
3 libdispatch.dylib 0x3b04ed3c _dispatch_client_callout + 20
4 libdispatch.dylib 0x3b0516be _dispatch_main_queue_callback_4CF + 274
5 CoreFoundation 0x3039b674 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 4
6 CoreFoundation 0x30399f40 __CFRunLoopRun + 1304
7 CoreFoundation 0x303047a4 CFRunLoopRunSpecific + 520
8 CoreFoundation 0x30304586 CFRunLoopRunInMode + 102
9 GraphicsServices 0x352716ce GSEventRunModal + 134
10 UIKit 0x32c6388c UIApplicationMain + 1132
11 my-app 0x00029dd4 main (main.m:16)
12 libdyld.dylib 0x3b063ab4 start + 0
As I understand it’s coming from addPeriodicTimeObserverForInterval:queue:usingBlock:, so I’m always checking for block and queue to be correct. What else can cause this?
Thanks in advance.
UPDATE:
Here is method that calls addPeriodicTimeObserverForInterval:queue:usingBlock:
- (void)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block
{
[block copy];
dispatch_async(self.operationQueue, ^{
//This method just makes sure, that self.player not nil
[self someMethodcompletionHandler:^{
if (self.observer) {
[self.player removeTimeObserver:self.observer];
self.observer = nil;
}
if (block && queue) {
self.observer = [self.player addPeriodicTimeObserverForInterval:interval
queue:queue
usingBlock:block];
}
}];
});
}
UPDATE 2:
I figured it out. But I don’t know, why that works. So my question, why it works? Why self.operationQueue better than just queue?
self.observer = [self.player addPeriodicTimeObserverForInterval:interval
queue:self.operationQueue
usingBlock:^(CMTime time){
dispatch_async(queue, ^{
block(time);
});
}];

Official AVPlayer documentation states:
Releasing the observer object without invoking removeTimeObserver: will result in undefined behavior
This means that you should keep the value returned from addPeriodicTimeObserverForInterval:queue:usingBlock: and before the observer block is released make sure that you call removeTimeObserver:
Also note that block objects are allocated on the stack by default (not the heap) so to be sure that your block is not released when the frame ends you should retain the block by calling copy.
To read more about block memory management see here.

Related

Possible reason for EXC_BAD_ACCESS?

I have a legacy app which utilizes Apple's example SimplePing. There is a source file SimplePing.m which contains the next method:
- (void)sendPingWithData:(NSData *)data {
id<SimplePingDelegate> strongDelegate;
...
strongDelegate = self.delegate;
if (...) {
[strongDelegate simplePing:self didSendPacket:...];
}
self.nextSequenceNumber += 1; // CRASH
if (self.nextSequenceNumber == 0) {
self.nextSequenceNumberHasWrapped = YES;
}
}
Crashlytics reports dozens of crashes with stack trace:
Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x00000009de3bbeb8
libobjc.A.dylib objc_msgSend + 16
MyApp SimplePing.m line 313 -[SimplePing sendPingWithData:]
Foundation __NSFireTimer + 88
CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 28
CoreFoundation __CFRunLoopDoTimer + 856
CoreFoundation __CFRunLoopDoTimers + 244
CoreFoundation __CFRunLoopRun + 1484
CoreFoundation CFRunLoopRunSpecific + 424
GraphicsServices GSEventRunModal + 100
UIKit UIApplicationMain + 208
MyApp main.swift line 10
libdyld.dylib start + 4
I have not managed to reprodice it yet, and I know a little about this app so far. But I have to begin researching it somehow. I looked through realization of delegates (btw, they are in Swift - if it's relevant), bit did not find anything criminal so far.
As I know, EXC_BAD_ACCESS normally fires when one tries to access deallocated memory. In this concrete case it could mean that [strongDelegate simplePing:self didSendPacket:...] has somehow deallocated self. But as self is a strong reference, it just could not happen at all - am I right?
May you guys drop me some probable scenarios on how could it crash with EXC_BAD_ACCESS on that line? The only my idea is that some memory overwrite have happened.
UPDATE
I was completely wrong with my assumption "But as self is a strong reference ...". self in nether strong, nor weak. It is just unsafe_unretained, as a smart guy explained: https://stackoverflow.com/a/18011581/674548.

Unexplainable crash on NSURLConnection

I get the following crash:
Exception Type: 00000020
Exception Codes: 0x000000008badf00d
Highlighted Thread: 0
Application Specific Information:
com.[app name].[app name] failed to scene-update in time
Elapsed total CPU time (seconds): 5.050 (user 5.050, system 0.000), 24% CPU
Elapsed application CPU time (seconds): 0.044, 0% CPU
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0:
0 libsystem_kernel.dylib 0x0000000195018e48 semaphore_wait_trap + 8
1 libdispatch.dylib 0x0000000194efbf3c _dispatch_semaphore_wait_slow + 252
2 CFNetwork 0x00000001832a2220 CFURLConnectionSendSynchronousRequest + 284
3 CFNetwork 0x00000001832c27c8 +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 116
4 Foundation 0x0000000184726358 -[NSData(NSData) initWithContentsOfURL:options:error:] + 308
5 Foundation 0x0000000184726204 +[NSData(NSData) dataWithContentsOfURL:options:error:] + 72
6 [app name] 0x00000001000b1a30 0x100090000 + 137776
7 [app name] 0x00000001001e3f44 0x100090000 + 1392452
8 libdispatch.dylib 0x0000000194eed990 _dispatch_call_block_and_release + 20
9 libdispatch.dylib 0x0000000194eed950 _dispatch_client_callout + 12
10 libdispatch.dylib 0x0000000194ef2208 _dispatch_main_queue_callback_4CF + 1604
11 CoreFoundation 0x00000001838962e8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
12 CoreFoundation 0x0000000183894390 __CFRunLoopRun + 1488
13 CoreFoundation 0x00000001837c11f0 CFRunLoopRunSpecific + 392
14 GraphicsServices 0x000000018cae36f8 GSEventRunModal + 164
15 UIKit 0x0000000188152108 UIApplicationMain + 1484
16 [app name] 0x00000001000dd2ac 0x100090000 + 316076
17 libdyld.dylib 0x0000000194f1aa04 start + 0
On the following code:
#try {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^(void) {
NSData* data = [NSData dataWithContentsOfURL:xxxxxxx options:NSDataReadingUncached error:&error];
...
[self.buffer performSelectorOnMainThread:#selector(addObject:) withObject:data waitUntilDone:YES];
}
#catch (NSException* error) {
NSLog(#"error: %#", error);
}
Yes there is a failure block too, but I simplified the code to the essence, the pure code that causes the crash.
This code runs hundreds of times per hour without any problem. But every now and then it crashes. Always the same crash (like the one above). First, the app freezes, then it crashes. The catch-block is never executed.
The performSelectorOnMainThread uses an object. And that object is added (in the main thread) to an NSMutableArray (self.buffer is an NSMutableArray). I know that NSMutableArrays are not thread-safe and that's why I perform them on the main thread. For waitUntilDone I use YES to prevent the thread from ending before the object is inserted. I used NO too, but that crashes constantly.
Does anyone have an idea why this crash happens? And do you perhaps have a solution for me to prevent this?
Thanks a lot.
You are doing network i/o on the main thread while updating the UI. This takes too long. Don't do that on the main thread. Instead, use an asynchronous way to run the URL fetch and cache the result so it can be used by the next user interface update.
More information:
https://developer.apple.com/library/ios/qa/qa1693/_index.html
Writing to the array on the main thread does not make it thread safe. Use a dedicated dispatch_queue to control access to the nsmutablearray instead, both read and write operations.
https://stackoverflow.com/a/4607664/573988

Sporadic Crash Resetting Persistent Stores Between Unit Test Cases (RestKit)

I apologize in advance that this probably won't end up contributing much to the general knowledge base here, but I'm looking for help diagnosing what's likely a configuration oversight that's causing my unit tests to crash sporadically.
I'm set up using RestKit with an in-memory object store while unit testing, so that after each test case, I can reset my persistent stores and each test can run with a fresh database. Much of the time my test suite runs without issue, but often enough to be a deal-breaker, there's a crash from what [I think] appears to be over-releasing a managed object context. All relevant code and crash data below:
Unit Test Base Class Setup
#implementation MyTestCase
- (void)setUp
{
[super setUp];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[MyObjectManager sharedManager] start];
});
}
- (void)tearDown
{
[super tearDown];
[[MyObjectManager sharedManager] reset];
}
Relevant MyObjectManager Setup
#interface MyObjectManager : RKObjectManager
- (void)start
{
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithPersistentStoreCoordinator:[self persistentStoreCoordinator]];
self.managedObjectStore = managedObjectStore;
[managedObjectStore createManagedObjectContexts];
[RKManagedObjectStore setDefaultStore:managedObjectStore];
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:kRDPersistentStore];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = #{
NSSQLitePragmasOption : #{
#"synchronous" : #"FULL",
#"fullfsync" : #(1)
},
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES
};
NSError *error = nil;
if (![self persistentStoreAtPath:storeURL options:options error:error])
{
NSLog(#"Error adding store %#: %#, %#", storeURL, error, [error userInfo]);
// Additional handling
}
return _persistentStoreCoordinator;
}
- (NSPersistentStore *)persistentStoreAtPath:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError *)error
{
// (NSSQLiteStoreType and storeUrl are used if we're not unit testing)
return [_persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:options
error:&error];
}
MyObjectManager::reset Implementation
- (void)reset
{
[[RKObjectManager sharedManager].operationQueue cancelAllOperations];
NSError *error = nil;
[[RKManagedObjectStore defaultStore] resetPersistentStores:&error];
if (error)
{
NSLog(#"Error! : %#", error);
}
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
Typical Crash Report
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGSEGV)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
iPhone Simulator 463.9.41, iPhone OS 7.1 (iPhone Retina (4-inch)/11D167)
Main thread is spinning the run loop, waiting on an asynchronous test case:
(Not always the case but a majority of our tests employ this method)
Thread : com.apple.main-thread
0 libsystem_kernel.dylib 0x047f6f92 semaphore_signal_trap + 10
1 libdispatch.dylib 0x0447f41f _dispatch_barrier_sync_f_slow_invoke + 54
2 libdispatch.dylib 0x044904d0 _dispatch_client_callout + 14
3 libdispatch.dylib 0x0447e726 _dispatch_main_queue_callback_4CF + 340
4 CoreFoundation 0x040fb43e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
5 CoreFoundation 0x0403c5cb __CFRunLoopRun + 1963
6 CoreFoundation 0x0403b9d3 CFRunLoopRunSpecific + 467
7 CoreFoundation 0x0403b7eb CFRunLoopRunInMode + 123
8 Foundation 0x03a71e35 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 284
9 Foundation 0x03a71cd5 -[NSRunLoop(NSRunLoop) runUntilDate:] + 88
10 Remind101-Tests 0x0cbb2c02 -[UTTestCase waitForBlockWithTimeout:] + 233
11 Remind101-Tests 0x0cbb2b14 -[UTTestCase waitForBlock] + 49
12 Remind101-Tests 0x0cbba55e -[UTAPITestCase sendRequestExpectingSuccess:] + 142
13 Remind101-Tests 0x0cb92832 -[UTMessageRequestTests testRequestCreatesFileEntities] + 166
14 CoreFoundation 0x0408a91d __invoking___ + 29
15 CoreFoundation 0x0408a82a -[NSInvocation invoke] + 362
16 XCTest 0x20103c6c -[XCTestCase invokeTest] + 221
17 XCTest 0x20103d7b -[XCTestCase performTest:] + 111
18 otest-shim-ios.dylib 0x0098fcc7 XCPerformTestWithSuppressedExpectedAssertionFailures + 172
19 otest-shim-ios.dylib 0x0098fc15 XCTestCase_performTest + 31
20 XCTest 0x20104c48 -[XCTest run] + 82
21 XCTest 0x201033e8 -[XCTestSuite performTest:] + 139
22 XCTest 0x20104c48 -[XCTest run] + 82
23 XCTest 0x201033e8 -[XCTestSuite performTest:] + 139
24 XCTest 0x20104c48 -[XCTest run] + 82
25 XCTest 0x201033e8 -[XCTestSuite performTest:] + 139
26 XCTest 0x20104c48 -[XCTest run] + 82
27 XCTest 0x201066ba +[XCTestProbe runTests:] + 183
28 Foundation 0x03a4b5ec __NSFireDelayedPerform + 372
29 CoreFoundation 0x04054ac6 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
30 CoreFoundation 0x040544ad __CFRunLoopDoTimer + 1181
31 CoreFoundation 0x0403c538 __CFRunLoopRun + 1816
32 CoreFoundation 0x0403b9d3 CFRunLoopRunSpecific + 467
33 CoreFoundation 0x0403b7eb CFRunLoopRunInMode + 123
34 GraphicsServices 0x057495ee GSEventRunModal + 192
35 GraphicsServices 0x0574942b GSEventRun + 104
36 UIKit 0x01e7ff9b UIApplicationMain + 1225
37 Remind101 0x0008d184 main (main.m:16)
38 libdyld.dylib 0x046c5701 start + 1
NSManagedObjectContext Queue thread crashes:
Thread : Crashed: NSManagedObjectContext Queue
0 libobjc.A.dylib 0x03e250be objc_msgSend + 26
1 CoreData 0x0108ffe3 developerSubmittedBlockToNSManagedObjectContextPerform_privateasync + 83
2 libdispatch.dylib 0x044904d0 _dispatch_client_callout + 14
3 libdispatch.dylib 0x0447e047 _dispatch_queue_drain + 452
4 libdispatch.dylib 0x0447de42 _dispatch_queue_invoke + 128
5 libdispatch.dylib 0x0447ede2 _dispatch_root_queue_drain + 78
6 libdispatch.dylib 0x0447f127 _dispatch_worker_thread2 + 39
7 libsystem_pthread.dylib 0x047bfdab _pthread_wqthread + 336
8 libsystem_pthread.dylib 0x047c3cce start_wqthread + 30
There's small variations in the stack of the crashed thread, but it always includes developerSubmittedBlockToNSManagedObjectContextPerform_privateasync in the last couple of frames before a bad objc_msgSend.
My initial hypothesis was that something in my codebase was accessing MyObjectManager.managedObjectContext from off the main thread, which as I understand would be a bad time. But I put in a condition to log and pause if the accessor was called from a thread that was not the main thread, which was never hit, so there goes my low-hanging fruit on that one.
I also tried putting some logging into the entry and exit points of instances of the asynchronous NSManagedObjectContext::performBlock function in the RestKit library to see if a block was running longer than expected, holding onto a reference to the context, and dereferencing it after it had been destroyed. I would have expected a entry log without an exit log if this was the issue, but I didn't see that. I didn't try the same with performBlockAndWait because I'm assuming all synchronous operations are complete by the time my test case finished and resets the persistent store.
I'm really at a loss for even how to go about continuing my investigation into this. I realize it's not a ton to go on, but if anyone has ideas or proposals for tracking this down, I'd be happy to provide more information and try literally anything to get this resolved.
Here's what developerSubmittedBlockToNSManagedObjectContextPerform_privateasync actually does:
Gets a reference to the managed object context from within the queue
Creates it's own autorelease pool
Executes the block
Calls _processRecentChanges: on the managed object context to processing any pending user events
Drains the autorelease pool
Releases the block (the block was copied before it was passed to this method)
If the block was NULL at this point that would be a problem, but you would have different symptoms. The only things here that would use objc_msgSend are the autorelease pool and the message to _processRecentChanges:.
You can try setting a symbolic breakpoint on -[NSManagedObjectContext _processRecentChanges:] and see if that gives you any clues. It's very likely that RestKit is making some invalid assumptions about the lifetime of a managed object context and it's getting over released in your case. If that is true, it's also likely that the opposite error is being made elsewhere - that contexts are being overretained. The two problems more often than not go hand in hand. Your question doesn't include the reported reason for the crash (exception, EXC_BAD_ACCESS, etc.), so it's difficult to be definitive.
_processRecentChanges: gets called a lot, so it may still take some time to track this down. The issue would be easier to troubleshoot with the newer developer tools - you should be able to see what submitted the crashing block and from what queue, and you should be able to use Instruments with your test case. It's likely that if you can reproduce this with the newer tools that you will make progress troubleshooting it much faster.

iOS Crash during background data processing when adding NSOperations to NSOperationQueue

My app is getting a 'random' crash when doing some background data processing. I am adding NSOperations (subclassed) to an array, then adding that array of NSOperations to a NSOperationQueue.
I am seeing 3-4 errors which all point to the this line in the stack trace:
[_operationQueue addOperations:_operationsArray waitUntilFinished:YES];
Here is how I am creating my NSOperations (LibSyncOperation) and adding them to _operationsArray, which eventually gets added to the _operationQueue
LibSyncOperation *libSyncOperation = [[LibSyncOperation alloc] initWithURL:path];
if(!libSyncOperation.isExecuting && !libSyncOperation.isFinished)
{
[_operationsArray addObject:libSyncOperation];
TFLog(#"Operation is *NOT* Executing, add to OperationQueue");
}
else
{
TFLog(#"Operation is already Executing, do not add to OperationQueue");
}
Here are some of the stack traces:
*** -[NSOperationQueue addOperations:waitUntilFinished:]: 3 (of 4) operations are finished, executing, or already in a queue, and cannot be enqueued
CoreFoundation-[NSException initWithCoder:]
0 CoreFoundation 0x18835f09c __exceptionPreprocess
1 libobjc.A.dylib 0x1947b5d78 objc_exception_throw
2 CoreFoundation 0x18835efdc -[NSException initWithCoder:]
3 Foundation 0x188ec1864 __addOperations
4 Foundation 0x188ec1bfc -[NSOperationQueue addOperations:waitUntilFinished:]
5 Tower-iSales-Tab 0x100223b54 __70-[NetworkManager checkForDataFilesShouldEmptyQueue:isInitialDownload:]_block_invoke_2183 in NetworkManager.m on Line 437
6 libdispatch.dylib 0x194d84420 _dispatch_call_block_and_release
7 libdispatch.dylib 0x194d843e0 _dispatch_client_callout
8 libdispatch.dylib 0x194d8b3fc _dispatch_root_queue_drain
9 libdispatch.dylib 0x194d8b638 _dispatch_worker_thread2
10 libsystem_pthread.dylib 0x194f19918 _pthread_wqthread
11 libsystem_pthread.dylib 0x194f197a8 start_wqthread
Another:
*** Collection <__NSMallocBlock__: 0x1784402a0> was mutated while being enumerated.
CoreFoundation
0 CoreFoundation 0x186226f50
1 libobjc.A.dylib 0x192c041fc objc_exception_throw
2 CoreFoundation 0x186226984
3 Foundation 0x186d91928 -[NSOperationQueue addOperations:waitUntilFinished:]
4 Tower-iSales-Tab 0x1002bbb54 __70-[NetworkManager checkForDataFilesShouldEmptyQueue:isInitialDownload:]_block_invoke_2183 in NetworkManager.m on Line 437
5 libdispatch.dylib 0x1931dc014 _dispatch_call_block_and_release
6 libdispatch.dylib 0x1931dbfd4 _dispatch_client_callout
7 libdispatch.dylib 0x1931e32b8 _dispatch_root_queue_drain
8 libdispatch.dylib 0x1931e34fc _dispatch_worker_thread2
9 libsystem_pthread.dylib 0x1933716bc _pthread_wqthread
10 libsystem_pthread.dylib 0x19337154c start_wqthread
Last One:
-[__NSBlockVariable__ countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x1782499c0
CoreFoundation__methodDescriptionForSelector
0 CoreFoundation 0x18835f09c __exceptionPreprocess
1 libobjc.A.dylib 0x1947b5d78 objc_exception_throw
2 CoreFoundation 0x188363d14 __methodDescriptionForSelector
3 CoreFoundation 0x188361a7c ___forwarding___
4 CoreFoundation 0x1882814ac __forwarding_prep_0___
5 Foundation 0x188ec1ca0 -[NSOperationQueue addOperations:waitUntilFinished:]
6 Tower-iSales-Tab 0x1002afb54 __70-[NetworkManager checkForDataFilesShouldEmptyQueue:isInitialDownload:]_block_invoke_2183 in NetworkManager.m on Line 437
7 libdispatch.dylib 0x194d84420 _dispatch_call_block_and_release
8 libdispatch.dylib 0x194d843e0 _dispatch_client_callout
9 libdispatch.dylib 0x194d8b3fc _dispatch_root_queue_drain
10 libdispatch.dylib 0x194d8b638 _dispatch_worker_thread2
11 libsystem_pthread.dylib 0x194f19918 _pthread_wqthread
12 libsystem_pthread.dylib 0x194f197a8 start_wqthread
Is there some obvious reason this crash would occur? I understand what the error message is saying, that NSOperations that are executing or finished cannot be enqueued again, the thing is, my _operationsArray is re-allocating anytime the update process runs, to ensure there are no NSOperations that were already enqueued hanging around.
One thing I am not doing, is re-allocating the NSOperationQueue each time, I figure that could be the cause, but since I cannot reproduce the error on my end (the users are experiencing this), I would like to know for sure. Heres the code for my NSOperationQueue (note this is all in a singleton class)
if(!_operationQueue)
_operationQueue = [[NSOperationQueue alloc]init];
[_operationQueue setMaxConcurrentOperationCount:1];
Could this be the culprit?
Any advice is appreciated. Thanks.
EDIT
As requested, heres the main for my LibSyncOperation:
-(void)main
{
if (![self isCancelled])
{
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:downloadURL cachePolicy:nil timeoutInterval:9999999];
NSURLConnection *downloadConnection = [[NSURLConnection alloc] initWithRequest:downloadRequest delegate:self];
[downloadConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[downloadConnection start];
if (downloadConnection)
{
do
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!downloadDone);
[self terminateOperation];
}
else
{
[self terminateOperation];
}
}
else
{
[self terminateOperation];
}
}

GCD dispatch_after call causing SIGBUS signal

I'm using GCD's dispatch_after method when my application is being loaded to perform some behavior. The intended behavior is to wait 3 seconds from the end of applicationDidFinishLaunchingWithOptions to perform a selector that runs in a background queue.
I haven't experienced any crashes on my test devices, but I have user crash reports of uncaught SIGBUS signals, the cause being a BUS_ADRALN exception. From my understanding of this code, a BUS_ADRALN error indicates an address alignment error.
This is how I'm creating my timer:
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
^(void){
[self methodToPerformInBackground];
});
What could be causing this crash?
Since multithreading errors can be a strange sort of beast, I'm going to throw out some ideas that I've been tossing around in my head.
I'm calling this from within a call to [self performSelectorOnMainThread:withObject:waitUntilDone]. Is there something problematic about doing this within a selector called this way?
Since I'm calling dispatch_get_global_queue and not dispatch_create_queue, I don't need to retain the queue returned by this method. Is this reasoning correct?
In this code, self is the application delegate. Could the crash be caused trying to perform the block after the application enters the background or terminates? Would the application automatically clean up any dispatched blocks upon closing?
Something inside the method being called is causing the crash, but GCD doesn't provide a stack trace to it.
Edit: I'd rather not include the code that's called in the block, since I'm not convinced that's the main problem anyway. Here is the stack trace. The crash on thread 0 makes it seem as though the issue was in GCD, not the code called in the block.
Edit #2: I have strange news to share after going through more crash reports. This crash is only appearing for users running iOS 4.2.X and below. Since GCD is supported for iOS 4.0 and later, my guess is there was a bug patched in 4.3.
Thread 0 Crashed:
0 libSystem.B.dylib 0x35e5fb10 _dispatch_retain + 0
1 libSystem.B.dylib 0x35e5df8c dispatch_after_f + 80
2 libSystem.B.dylib 0x35e5e070 dispatch_after + 72
3 MyApplication 0x0000466c -[MyApplicationDelegate applicationDidFinishLaunchingPart2:] (MyApplicationDelegate.m:366)
4 CoreFoundation 0x37538f79 -[NSObject(NSObject) performSelector:withObject:] + 25
5 Foundation 0x35171e6d __NSThreadPerformPerform + 273
6 CoreFoundation 0x375518d1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
7 CoreFoundation 0x37521ecd __CFRunLoopDoSources0 + 385
8 CoreFoundation 0x375216f9 __CFRunLoopRun + 265
9 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 227
10 CoreFoundation 0x37521419 CFRunLoopRunInMode + 61
11 GraphicsServices 0x33e76d24 GSEventRunModal + 196
12 UIKit 0x3591d57c -[UIApplication _run] + 588
13 UIKit 0x3591a558 UIApplicationMain + 972
14 MyApplication 0x00003024 main (main.m:113)
Thread 1:
0 libSystem.B.dylib 0x35d8f974 kevent + 24
1 libSystem.B.dylib 0x35e5dd70 _dispatch_queue_invoke + 104
2 libSystem.B.dylib 0x35e5d790 _dispatch_worker_thread2 + 128
3 libSystem.B.dylib 0x35de6978 _pthread_wqthread + 400
Thread 2:
0 libSystem.B.dylib 0x35de72fc __workq_kernreturn + 8
Thread 3:
0 libSystem.B.dylib 0x35d5b3b0 mach_msg_trap + 20
1 CoreFoundation 0x37521f83 __CFRunLoopServiceMachPort + 95
2 CoreFoundation 0x37521787 __CFRunLoopRun + 407
3 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 227
4 CoreFoundation 0x37521419 CFRunLoopRunInMode + 61
5 WebCore 0x3318bd1c _ZL12RunWebThreadPv + 532
6 libSystem.B.dylib 0x35de5b4c _pthread_start + 372
Thread 4:
0 libSystem.B.dylib 0x35d5b3b0 mach_msg_trap + 20
1 CoreFoundation 0x37521f83 __CFRunLoopServiceMachPort + 95
2 CoreFoundation 0x37521787 __CFRunLoopRun + 407
3 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 227
4 CoreFoundation 0x37521419 CFRunLoopRunInMode + 61
5 Foundation 0x3517ec55 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 217
6 Foundation 0x3515cb91 -[NSThread main] + 49
7 Foundation 0x35155b97 __NSThread__main__ + 915
8 libSystem.B.dylib 0x35de5b4c _pthread_start + 372
DISPATCH_QUEUE_PRIORITY_BACKGROUND is an iOS 5.0+ feature. If you try to use it on iOS 4.x it will be NULL (which will crash when you try to retain it, since GCD is a C-library and it is not safe to use NULL the way it is to use nil in objective-c). See this answer for more info. The solution is to use low priority instead, or use preprocessor directives to switch between the two.

Resources