From 3597458934e4b010527b0f53e0e56132246876d9 Mon Sep 17 00:00:00 2001 From: David Grove Date: Mon, 24 Oct 2016 15:40:43 -0400 Subject: [PATCH] SR-3002: DispatchData.enumerateBytes on Linux leaks the block To avoid leaking the block parameter of enumerateBytes, we need to directly call CDispatch.dispatch_data_apply (not _swift_dispatch_data_apply). However, we need to tell the compiler that the internal closure that translates between the C and Swift layers will not cause the captured block parameter to escape. If SR-2313 were implemented, we could use withoutActuallyEscaping. Since withoutActuallyEscaping is not available, we instead use unsafeBitCast to bypass the compiler's analysis. --- src/swift/Data.swift | 11 +++++------ src/swift/DispatchStubs.cc | 6 ------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/swift/Data.swift b/src/swift/Data.swift index 6437ea48c..fc0bc0944 100644 --- a/src/swift/Data.swift +++ b/src/swift/Data.swift @@ -91,11 +91,13 @@ public struct DispatchData : RandomAccessCollection { public func enumerateBytes( block: (_ buffer: UnsafeBufferPointer, _ byteIndex: Int, _ stop: inout Bool) -> Void) { - _swift_dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in + // FIXME: When SR-2313 (withoutActuallyEscaping) is implemented, use it to replace unsafeBitCast + let nonEscapingBlock = unsafeBitCast(block, to: _enumerateBytesBlock.self) + _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size) let bp = UnsafeBufferPointer(start: bytePtr, count: size) var stop = false - block(bp, offset, &stop) + nonEscapingBlock(bp, offset, &stop) return !stop } } @@ -271,10 +273,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence { internal var _position: DispatchData.Index } -typealias _swift_data_applier = @convention(block) (dispatch_data_t, Int, UnsafeRawPointer, Int) -> Bool - -@_silgen_name("_swift_dispatch_data_apply") -internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier) +typealias _enumerateBytesBlock = (_ buffer: UnsafeBufferPointer, _ byteIndex: Int, _ stop: inout Bool) -> Void @_silgen_name("_swift_dispatch_data_empty") internal func _swift_dispatch_data_empty() -> dispatch_data_t diff --git a/src/swift/DispatchStubs.cc b/src/swift/DispatchStubs.cc index ae8229928..c903d69ea 100644 --- a/src/swift/DispatchStubs.cc +++ b/src/swift/DispatchStubs.cc @@ -141,12 +141,6 @@ _swift_dispatch_block_testcancel(dispatch_block_t block) { return dispatch_block_testcancel(block); } -SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE -extern "C" bool -_swift_dispatch_data_apply(dispatch_data_t data, bool (^applier)(dispatch_data_t, size_t, const void *, size_t)) { - return dispatch_data_apply(data, applier); -} - SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE extern "C" void _swift_dispatch_async(dispatch_queue_t queue, dispatch_block_t block) {