NSDocument(NSDocumentSaving) bad access

I'm getting random crashes in a background thread in my document-based app.

NSDocument(NSDocumentSaving) causes EXC_BAD_ACCESS (SIGSEGV) / KERN_INVALID_ADDRESS

Thread 10 Crashed:: Dispatch queue: com.apple.root.default-qos
0   libobjc.A.dylib               	0x00007fff2020581d objc_msgSend + 29
1   com.apple.AppKit              	0x00007fff237b1909 __85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_4.860 + 245
2   libdispatch.dylib             	0x00007fff201bc623 _dispatch_call_block_and_release + 12
3   libdispatch.dylib             	0x00007fff201bd806 _dispatch_client_callout + 8
4   libdispatch.dylib             	0x00007fff201bfe37 _dispatch_queue_override_invoke + 775
5   libdispatch.dylib             	0x00007fff201cc818 _dispatch_root_queue_drain + 326
6   libdispatch.dylib             	0x00007fff201ccf70 _dispatch_worker_thread2 + 92
7   libsystem_pthread.dylib       	0x00007fff20364417 _pthread_wqthread + 244
8   libsystem_pthread.dylib       	0x00007fff2036342f start_wqthread + 15

I'm wondering how I could start debugging the issue, and need some help with deciphering the crash log.

Am I correct, that based on the error log, the NSDocument which is being saved does exist?

In that case, it would be just some other variable which has disappeared somewhere, meaning either the NSURL or completionHandler? Or is the whole NSDocument a corpse at this point?

The crash occurs very randomly, so it's pretty hard to reproduce reliably.

EDIT: I found a GitHub issue with the exact same problem. Their research points to this being a race condition, which occurs when asynchronous autosave is in progress and an edit to NSDocument is being performed.

However, if I disallow asynchronous autosaves (canAsynchronouslyWriteToURL), drafts don't seem to get saved at all.

Is there anything I can do to prevent the asynchronous race condition?

Answered by tritonus in 691473022

Asynchronous saving seems to result in weird thread safety problems that are not really covered by NSDocument documentation, or even discussed anywhere. So, for anyone else struggling with this:

In your dataOfType: method, be careful not to fetch anything, which could be mutating while an edit is made. This is the basic solution, but apparently it's more complicated than that.

I still haven't resolved the issue completely, and have to go through thousands of lines of code to find possible culprits for this thread un-safety. I tried to make a buffer/cache which only gets updated when an edit has been made, and in dataOfType: I also made sure to make copies of that data. This doesn't help, because it's still completely possible that the data was altered on the same millisecond, causing a new race condition.

Accepted Answer

Asynchronous saving seems to result in weird thread safety problems that are not really covered by NSDocument documentation, or even discussed anywhere. So, for anyone else struggling with this:

In your dataOfType: method, be careful not to fetch anything, which could be mutating while an edit is made. This is the basic solution, but apparently it's more complicated than that.

I still haven't resolved the issue completely, and have to go through thousands of lines of code to find possible culprits for this thread un-safety. I tried to make a buffer/cache which only gets updated when an edit has been made, and in dataOfType: I also made sure to make copies of that data. This doesn't help, because it's still completely possible that the data was altered on the same millisecond, causing a new race condition.

NSDocument(NSDocumentSaving) bad access
 
 
Q