From 75ba01b0539495a98f460ea95486994dafc05500 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 e81ea99fc..22b3d33ef 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -66,7 +66,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 { @@ -111,7 +115,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. @@ -248,7 +252,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 974d2f64a..00076ec18 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 367c59abc..dccc86885 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()) + } } }