Skip to content

Commit

Permalink
Fixed potential crash in rare cases when Core MIDI property getter pr…
Browse files Browse the repository at this point in the history
…oduces an error
  • Loading branch information
orchetect committed Nov 9, 2023
1 parent be3342e commit 308701b
Showing 1 changed file with 17 additions and 22 deletions.
39 changes: 17 additions & 22 deletions Sources/MIDIKitIO/Core MIDI/Core MIDI Properties Get.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,20 @@ func getProperties(
let result = MIDIObjectGetProperties(ref, &props, deep)

guard result == noErr else {
props?.release()
throw MIDIIOError.osStatus(result)
}

guard let unwrappedProps = props?.takeRetainedValue() else {
props?.release()
throw MIDIIOError.readError(
"Got nil while reading MIDIEndpointRef property list."
)
}

// "takeRetainedValue() is the right choice here because it is the caller's responsibility to
// release the string.
// This is different from the usual Core Foundation memory management rules, but documented in
// the MIDI Services Reference"
// -- https://stackoverflow.com/a/27171498/2805570
// This is different from the usual Core Foundation memory management rules, but documented in
// the MIDI Services Reference."
// -- https://stackoverflow.com/a/27171498/2805570

return unwrappedProps
}
Expand All @@ -55,29 +53,27 @@ func getProperties(
///
/// - Throws: ``MIDIIOError``
func getDictionary(
forProperty: CFString,
forProperty property: CFString,
of ref: CoreMIDI.MIDIObjectRef
) throws -> NSDictionary {
var dict: Unmanaged<CFDictionary>?
let result = MIDIObjectGetDictionaryProperty(ref, forProperty, &dict)
let result = MIDIObjectGetDictionaryProperty(ref, property, &dict)

guard result == noErr else {
dict?.release()
throw MIDIIOError.osStatus(result)
}

guard let unwrappedDict = dict?.takeRetainedValue() else {
dict?.release()
throw MIDIIOError.readError(
"Got nil while reading MIDIEndpointRef property list."
)
}

// "takeRetainedValue() is the right choice here because it is the caller's responsibility to
// release the string.
// This is different from the usual Core Foundation memory management rules, but documented in
// the MIDI Services Reference"
// -- https://stackoverflow.com/a/27171498/2805570
// This is different from the usual Core Foundation memory management rules, but documented in
// the MIDI Services Reference."
// -- https://stackoverflow.com/a/27171498/2805570

return unwrappedDict as NSDictionary
}
Expand All @@ -91,29 +87,27 @@ func getDictionary(
///
/// - Throws: ``MIDIIOError``
func getString(
forProperty: CFString,
forProperty property: CFString,
of ref: CoreMIDI.MIDIObjectRef
) throws -> String {
var val: Unmanaged<CFString>?
let result = MIDIObjectGetStringProperty(ref, forProperty, &val)
let result = MIDIObjectGetStringProperty(ref, property, &val)

guard result == noErr else {
val?.release()
throw MIDIIOError.osStatus(result)
}

guard let unwrappedVal = val?.takeRetainedValue() else {
val?.release()
throw MIDIIOError.readError(
"Got nil while reading MIDIEndpointRef property value \((forProperty as String).quoted)"
"Got nil while reading MIDIEndpointRef property value \((property as String).quoted)"
)
}

// "takeRetainedValue() is the right choice here because it is the caller's responsibility to
// release the string.
// This is different from the usual Core Foundation memory management rules, but documented in
// the MIDI Services Reference"
// -- https://stackoverflow.com/a/27171498/2805570
// This is different from the usual Core Foundation memory management rules, but documented in
// the MIDI Services Reference."
// -- https://stackoverflow.com/a/27171498/2805570

return unwrappedVal as String
}
Expand All @@ -123,11 +117,12 @@ func getString(
///
/// - Parameter forProperty: a `CoreMIDI.Property` constant
func getInteger(
forProperty: CFString,
forProperty property: CFString,
of ref: CoreMIDI.MIDIObjectRef
) -> Int32 {
var val: Int32 = 0
_ = MIDIObjectGetIntegerProperty(ref, forProperty, &val)
// TODO: handle OSStatus errors?
_ = MIDIObjectGetIntegerProperty(ref, property, &val)
return val
}

Expand Down

0 comments on commit 308701b

Please sign in to comment.