I was trying to debug an exc_bad_access problem in my AudioToolbox-based app and decided to enable the AddressSanitizer. Interestingly, it found a more general problem with a stack buffer overflow happening in a function for writing user events to a MusicTrack (i.e., MusicTrackNewUserEvent). There's nothing very special about my function:
func addUserEventToSequence(event: Event, sequence: MusicSequence, track: MusicTrack) {
var tempEvent = event
_ = withEventOfType(for: &tempEvent.self, body: { eventUserData in
MusicTrackNewUserEvent(track, event.timestamp, eventUserData)
})
}
where withEventOfType is just:
func withEventOfType<T>(for eventPtr: UnsafePointer<Event>, body: (_ data: UnsafePointer<MusicEventUserData>) throws -> T) rethrows -> T {
let dataLength = eventPtr.pointee.length
return try eventPtr.withMemoryRebound(to: MusicEventUserData.self, capacity: 8 + Int(dataLength), { eventAsBytes in
return try body(eventAsBytes)
})
}
...and "Event" is a custom struct for holding music data required by our app. I've always thought user events were intended to be used for arbitrary data, but I realize now that I've never been very conscious of the data length when using them. There is a length property, of course, and I do set it when I create the event.
Event = Event(length: UInt32(MemoryLayout<Event>.size), typeID: 3, trackID: UInt32(0), pitch: UInt8(0), velocity: UInt8(0), channel: UInt8(0), timestamp: beat, duration: 0, barBeat: nil)
(I realize that data looks strange—this is just a running beat count that I'm using for other purposes. Here I could use a different type, but this is just one specific example; the problem is more general.)
Presumably I'm misunderstanding something here... (??)
Any thoughts appreciated.