From 3efce580f8bccb5a9210c9742800cbc9d62bd8ec Mon Sep 17 00:00:00 2001 From: David Grove Date: Thu, 22 Sep 2016 17:00:55 -0400 Subject: [PATCH] SR-2656: extra releases of dispatch_data_t objects on Linux Fixes an over-release problem in the wrapping overlay that occurred in callback blocks that take DispatchData structs. Just going through the glue layer between the Swift and C APIs should not result in a net change in the reference count of the dispatch_data_t object that the CDispatch layer is giving us to hand to the Swift callback block. However, when the temporary DispatchData struct we created in the wrapping layer (and its wrapped __DispatchData object) went out of scope at the end of the callback, the dispatch_data_t was released by __DispatchData's deinit resulting in an unintended net -1 from the glue code. We either need to add a compensating retain before entering the callback block or suppress the release in the deinit. This patch suppresses the release by adding an internal init that can create DispatchData's with borrowed dispatch_data_t objects that are not released on deinitialization. --- src/swift/Data.swift | 10 +++++++--- src/swift/IO.swift | 8 ++++---- src/swift/Wrapper.swift | 8 ++++++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index 7acf50d65..6437ea48c 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -65,7 +65,11 @@ public struct DispatchData : RandomAccessCollection { } internal init(data: dispatch_data_t) { - __wrapped = __DispatchData(data: data) + __wrapped = __DispatchData(data: data, owned: true) + } + + internal init(borrowedData: dispatch_data_t) { + __wrapped = __DispatchData(data: borrowedData, owned: false) } public var count: Int { @@ -110,7 +114,7 @@ public struct DispatchData : RandomAccessCollection { /// - parameter data: The data to append to this data. public mutating func append(_ other: DispatchData) { let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped) - __wrapped = __DispatchData(data: data) + __wrapped = __DispatchData(data: data, owned: true) } /// Append a buffer of bytes to the data. @@ -244,7 +248,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { public init(_data: DispatchData) { var ptr: UnsafeRawPointer? self._count = 0 - self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count)) + self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count), owned: true) self._ptr = ptr self._position = _data.startIndex diff --git a/src/swift/IO.swift b/src/swift/IO.swift index 10c719919..8ce417aa7 100644 --- a/src/swift/IO.swift +++ b/src/swift/IO.swift @@ -36,13 +36,13 @@ public extension DispatchIO { public class func read(fromFileDescriptor: Int32, maxLength: Int, runningHandlerOn queue: DispatchQueue, handler: @escaping (_ data: DispatchData, _ error: Int32) -> Void) { dispatch_read(fromFileDescriptor, maxLength, queue.__wrapped) { (data: dispatch_data_t, error: Int32) in - handler(DispatchData(data: data), error) + handler(DispatchData(borrowedData: data), error) } } public class func write(toFileDescriptor: Int32, data: DispatchData, runningHandlerOn queue: DispatchQueue, handler: @escaping (_ data: DispatchData?, _ error: Int32) -> Void) { dispatch_write(toFileDescriptor, data.__wrapped.__wrapped, queue.__wrapped) { (data: dispatch_data_t?, error: Int32) in - handler(data.flatMap { DispatchData(data: $0) }, error) + handler(data.flatMap { DispatchData(borrowedData: $0) }, error) } } @@ -77,13 +77,13 @@ public extension DispatchIO { public func read(offset: off_t, length: Int, queue: DispatchQueue, ioHandler: @escaping (_ done: Bool, _ data: DispatchData?, _ error: Int32) -> Void) { dispatch_io_read(self.__wrapped, offset, length, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in - ioHandler(done, data.flatMap { DispatchData(data: $0) }, error) + ioHandler(done, data.flatMap { DispatchData(borrowedData: $0) }, error) } } public func write(offset: off_t, data: DispatchData, queue: DispatchQueue, ioHandler: @escaping (_ done: Bool, _ data: DispatchData?, _ error: Int32) -> Void) { dispatch_io_write(self.__wrapped, offset, data.__wrapped.__wrapped, queue.__wrapped) { (done: Bool, data: dispatch_data_t?, error: Int32) in - ioHandler(done, data.flatMap { DispatchData(data: $0) }, error) + ioHandler(done, data.flatMap { DispatchData(borrowedData: $0) }, error) } } diff --git a/src/swift/Wrapper.swift b/src/swift/Wrapper.swift index ea340e20c..9c96c0eed 100644 --- a/src/swift/Wrapper.swift +++ b/src/swift/Wrapper.swift @@ -192,17 +192,21 @@ extension DispatchSource : DispatchSourceProcess, internal class __DispatchData : DispatchObject { internal let __wrapped:dispatch_data_t + internal let __owned:Bool final internal override func wrapped() -> dispatch_object_t { return unsafeBitCast(__wrapped, to: dispatch_object_t.self) } - internal init(data:dispatch_data_t) { + internal init(data:dispatch_data_t, owned:Bool) { __wrapped = data + __owned = owned } deinit { - _swift_dispatch_release(wrapped()) + if __owned { + _swift_dispatch_release(wrapped()) + } } }