"-com.apple.CoreData.ConcurrencyDebug 1" crashes iOS app according to its name on iOS 14

It's hard to believe, but when using the run argument "-com.apple.CoreData.ConcurrencyDebug 1", the app would crash consistently just because its name (PRODUCT_NAME variable in Xcode build settings) starts with "Music" or "Musik". Simply changing the target name prevents the crash.

This issue started appearing only on iOS 14.0

To reproduce:
Use Xcode 12.01 to create a new project -> iOS -> App. Use Core Data and Objective-c in the wizard settings.
  • Enter an app name which is starting with "Music" or "Musik". For example "MusicTest".

  • Place "-com.apple.CoreData.ConcurrencyDebug 1" in the scheme run arguments.

  • Add a new entity to the data model named "TestEnt"

  • Add the following code to the end of the AppDelegate.m file.

Code Block
- (void)test {
  // ---
  // Set run argument in the scheme as follow:
  // -com.apple.CoreData.ConcurrencyDebug 1
  // ---
  NSLog(@"TEST");
  dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
    NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
    [managedObjectContext performBlockAndWait:^{
      NSError *error = nil;
      NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"TestEnt"];
      NSArray *result = [managedObjectContext executeFetchRequest:request error:&error];
      NSLog(@"result=%@", result);
    }];
  });
}
- (NSManagedObjectContext *)managedObjectContext {
   
  // The old-fashion way to create a managed object conttext
   
  NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
  NSString *storeFilePath = [[documentsDir stringByAppendingPathComponent:@"MusicTest"] stringByAppendingPathExtension:@"sqlite"];
  NSURL *storeURL = [NSURL fileURLWithPath:storeFilePath];
   
   
  NSURL *objectModelURL = [[NSBundle mainBundle] URLForResource:@"MusicTest"
                          withExtension:@"momd"];
  NSManagedObjectModel *objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:objectModelURL];
   
  NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel];
   
  NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @YES,
               NSInferMappingModelAutomaticallyOption: @YES};
  NSError *error = nil;
  [coordinator addPersistentStoreWithType:NSSQLiteStoreType
               configuration:nil
                    URL:storeURL
                  options:options
                   error:&error];
   
  NSManagedObjectContext *managedObjectContext = nil;
  if (coordinator != nil) {
    managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    managedObjectContext.persistentStoreCoordinator = coordinator;
    managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
  }
   
  return managedObjectContext;
}

  • Modify code on ViewController.m as follow:

Code Block
- (void)viewDidLoad {
  [super viewDidLoad];
   
  [(AppDelegate *)UIApplication.sharedApplication.delegate test];
}

  • Run project and view crash coming.

Code Block
Multithreading_Violation_AllThatIsLeftToUsIsHonor
  • Select MusicTest project on the project navigator.

  • Rename "MusicTest" appearing under "TARGETS" on the main window to "MyMusicTest"

  • Run project again

  • No crash this time.

Did Anyone encounter this issue? Can someone from Apple kindly reply?

Accepted Reply

I get the same result. This looks like an internal issue that probably affects at least some other app names that begin with the same letters as Apple's iOS apps.

Here's a workaround that may help. Look at the full stack trace when the assertion happens:

Code Block
* thread #2, queue = 'com.apple.root.user-initiated-qos', stop reason = EXC_BREAKPOINT (code=1, subcode=0x184e68d68)
* frame #0: 0x0000000184e68d68 CoreData`+[NSManagedObjectContext Multithreading_Violation_AllThatIsLeftToUsIsHonor] + 12
frame #1: 0x0000000184e68c4c CoreData`_PFAssertSafeMultiThreadedAccess_impl + 548
frame #2: 0x0000000184e68a24 CoreData`__68-[NSManagedObjectContext _PFAutoreleasePoolReferenceQueueTrampoline]_block_invoke + 92
frame #3: 0x0000000184e32b2c CoreData`-[_PFAutoreleasePoolThunk dealloc] + 40
frame #4: 0x00000001801858e8 libobjc.A.dylib`AutoreleasePoolPage::releaseUntil(objc_object**) + 204
frame #5: 0x00000001801857b8 libobjc.A.dylib`objc_autoreleasePoolPop + 236
frame #6: 0x00000001024f8fac libdispatch.dylib`_dispatch_last_resort_autorelease_pool_pop + 40
frame #7: 0x000000010250b37c libdispatch.dylib`_dispatch_root_queue_drain + 1428
frame #8: 0x000000010250b928 libdispatch.dylib`_dispatch_worker_thread2 + 136
frame #9: 0x00000001bad2175c libsystem_pthread.dylib`_pthread_wqthread + 212


Notice that frames near the middle of the pile mention autoreleasing. That suggests a course of action, since if you can affect how things are autoreleased in the framework, you might change the behavior. And in fact if you add @autoreleasepool to your performBlockAndWait:

Code Block
[managedObjectContext performBlockAndWait:^{
@autoreleasepool {
NSError *error = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"TestEnt"];
NSArray *result = [managedObjectContext executeFetchRequest:request error:&error];
NSLog(@"result=%@", result);
}
}];


...the violation goes away. I don't know if this will help in your real code as well as in your demo code, but it may be worth a try.

Replies

I get the same result. This looks like an internal issue that probably affects at least some other app names that begin with the same letters as Apple's iOS apps.

Here's a workaround that may help. Look at the full stack trace when the assertion happens:

Code Block
* thread #2, queue = 'com.apple.root.user-initiated-qos', stop reason = EXC_BREAKPOINT (code=1, subcode=0x184e68d68)
* frame #0: 0x0000000184e68d68 CoreData`+[NSManagedObjectContext Multithreading_Violation_AllThatIsLeftToUsIsHonor] + 12
frame #1: 0x0000000184e68c4c CoreData`_PFAssertSafeMultiThreadedAccess_impl + 548
frame #2: 0x0000000184e68a24 CoreData`__68-[NSManagedObjectContext _PFAutoreleasePoolReferenceQueueTrampoline]_block_invoke + 92
frame #3: 0x0000000184e32b2c CoreData`-[_PFAutoreleasePoolThunk dealloc] + 40
frame #4: 0x00000001801858e8 libobjc.A.dylib`AutoreleasePoolPage::releaseUntil(objc_object**) + 204
frame #5: 0x00000001801857b8 libobjc.A.dylib`objc_autoreleasePoolPop + 236
frame #6: 0x00000001024f8fac libdispatch.dylib`_dispatch_last_resort_autorelease_pool_pop + 40
frame #7: 0x000000010250b37c libdispatch.dylib`_dispatch_root_queue_drain + 1428
frame #8: 0x000000010250b928 libdispatch.dylib`_dispatch_worker_thread2 + 136
frame #9: 0x00000001bad2175c libsystem_pthread.dylib`_pthread_wqthread + 212


Notice that frames near the middle of the pile mention autoreleasing. That suggests a course of action, since if you can affect how things are autoreleased in the framework, you might change the behavior. And in fact if you add @autoreleasepool to your performBlockAndWait:

Code Block
[managedObjectContext performBlockAndWait:^{
@autoreleasepool {
NSError *error = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"TestEnt"];
NSArray *result = [managedObjectContext executeFetchRequest:request error:&error];
NSLog(@"result=%@", result);
}
}];


...the violation goes away. I don't know if this will help in your real code as well as in your demo code, but it may be worth a try.
atomicbird, thank you for your reply. I wasn't sure if anyone also encountered this issue, so I guess I'm not alone here.

I tried your workaround and it works very well on the demo project (thank you for this!). The problem is that my app uses a 3rd party library with deep Core Data integration. I have the source code of this library, however, there are hundreds of performBlockAndWait blocks in this library, so adding @autoreleasepool inside each of them is not very practical.

Did you report this issue or got in touch with Apple about it? I submitted a report at https://feedbackassistant.apple.com/feedback/8761671 and also opened a ticket with Apple code level support in order to accelerate the process of fixing this.

I am not sure how to move forward. I doubt it will be fixed soon by Apple.

I consider to temporary change my app name to workaround this issue (e.g. from "Music Library" to "My Music Library") however I'm not sure that this is a good idea. Changing the PRODUCT_NAME build setting in my Xcode project might cause unpredicted runtime results as this variable is probably widely used across the high level and low level app code.

Any suggestions?