EXC_BAD_INSTRUCTION when deallocating dispatch_source_t from within init()

Why does this crash?


import Cocoa
struct Something {
  var timer: dispatch_source_t? = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT)
}
var s = Something()
s.timer = nil // CRASH EXC_BAD_INSTRUCTION


And this?


import Cocoa
struct Something {
  var timer: dispatch_source_t?

  init() {
       timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT)
       timer = nil
  }
}
let s = Something() // CRASH EXC_BAD_INSTRUCTION


There’s lots of related variants I can get to crash – seems setting a property of type dispatch_source_t within a constructor causes EXC_BAD_INSTRUCTION.

I discovered this in an NSDocument subclass I have that creates a timer, but if reading from file fails and throws and exception, it crashes with EXC_BAD_INSTRUCTION while destroying the document.


Something interesting I found: creating and destroying an unrelated timer seems to stop it crashing?


import Cocoa
var someOtherUnrelatedTimer: dispatch_source_t? = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT)
someOtherUnrelatedTimer = nil

struct Something {
  var timer: dispatch_source_t? = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT)
}
var s = Something()
s.timer = nil // Doesn’t crash, when someOtherUnrelatedTimer = nil, above


What’s going on here? I’m not just going crazy and missing something, am I?

Filed rdar://23718983

Accepted Reply

I just found the answer to my question, in this other thread from a month ago: https://forums.developer.apple.com/message/46175#46175

    dispatch_source_cancel(dispatchSource);
    dispatch_resume(dispatchSource);

https://devforums.apple.com/message/1105979#1105979


So, this example does not crash anymore:


import Cocoa
struct Something {

  var timer: dispatch_source_t?

  init() {
       timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT)
       dispatch_source_cancel(timer!)
       dispatch_resume(timer!)
       timer = nil
  }
}
let s = Something() // Does not crash anymore



In my original NSDocument subclass that started all this, I have added this in deinit, so if it is destroyed by an exception handler at any point, it will be cleaned up properly.


  deinit {
       if let t = timer {
            dispatch_source_cancel(t)
            dispatch_resume(t)
       }
  }

Replies

I just found the answer to my question, in this other thread from a month ago: https://forums.developer.apple.com/message/46175#46175

    dispatch_source_cancel(dispatchSource);
    dispatch_resume(dispatchSource);

https://devforums.apple.com/message/1105979#1105979


So, this example does not crash anymore:


import Cocoa
struct Something {

  var timer: dispatch_source_t?

  init() {
       timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT)
       dispatch_source_cancel(timer!)
       dispatch_resume(timer!)
       timer = nil
  }
}
let s = Something() // Does not crash anymore



In my original NSDocument subclass that started all this, I have added this in deinit, so if it is destroyed by an exception handler at any point, it will be cleaned up properly.


  deinit {
       if let t = timer {
            dispatch_source_cancel(t)
            dispatch_resume(t)
       }
  }