János
János

Reputation: 35114

Why NSMutableDictionary setValue crashes?

setValue(_:forKey:) method crashes sometimes. Our NSMutableDictionary is written only from main thread, but it is often accessed. Can frequent access of dictionary cause a crash?

I guess with Core Data changing data would be more robost, but we decided to use dictionary based persistent storage. Is it any way to make more reliable accessing our NSMutableDictionary?

Anyway how could I figure out which setValue method crash if they are executed in a loop? If I print keyPath, end of loop will be reached before the crash happen, so I can not narrow down which setValue call exactly cause the crash.

Upvotes: 1

Views: 2084

Answers (2)

Dániel Nagy
Dániel Nagy

Reputation: 12045

If I understood it correctly, your setup is something like this: writing only on the main thread but reading from another threads. With this setup:

let a = NSMutableDictionary()
let time = DispatchTime.now() + 0.01
DispatchQueue.global().asyncAfter(deadline: time) {
    for _ in 0..<10000000000000 {
        let b = self.a["\(self.a.count - 1)"]
        print(b)
    }
}

for index in 0..<1000000000000000 {
    a.setValue(NSNumber(value: index), forKey: "\(index)")
}

I was indeed able to reproduce your issue. Here is the stack trace when the crash is happening:

Thread 1 Queue : com.apple.main-thread (serial)
#0  0x00000001115286f6 in _kernelrpc_mach_vm_deallocate_trap ()
#1  0x0000000111530a43 in mach_vm_deallocate ()
#2  0x00000001112c8477 in mvm_deallocate_pages ()
#3  0x00000001112bfdc4 in free_large ()
#4  0x000000010cc5506b in mdict_rehashd ()
#5  0x000000010cac26c6 in -[__NSDictionaryM setObject:forKey:] ()
#6  0x000000010b9382f5 in ViewController.viewDidLoad() at 

Thread 5 Queue : com.apple.root.default-qos (concurrent)
#0  0x000000010cafc454 in -[__NSDictionaryM objectForKey:] ()
#1  0x000000010d11567b in NSMutableDictionary.subscript.getter ()
#2  0x000000010d115588 in @objc NSDictionary.subscript.getter ()
#3  0x000000010b93898d in closure #1 in ViewController.viewDidLoad() at 

From the deallocations on the main thread I guess setValue caused some rebucketing on the dictionary, and as a reading happening at the same time, it tries to read deallocated memory -> EXC_BAD_ACCESS. Wrapping up: this should be a concurrency issue.

Upvotes: 1

LGP
LGP

Reputation: 4333

It is more likely the problem elsewhere. Try setting a breakpoint on exception instead. That way Xcode will stop when it happens.

In the breakpoint navigator choose Exception breakpoint..., see picture below.

Note that you might stop at other exceptions too, if they are handled they are not errors. In such case, just continue running.

enter image description here

Upvotes: 0

Related Questions