Skip to content

Commit 12b4373

Browse files
dgrove-ossdas
authored andcommitted
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. Signed-off-by: Daniel A. Steffen <dsteffen@apple.com>
1 parent db9cab8 commit 12b4373

File tree

2 files changed

+5
-12
lines changed

2 files changed

+5
-12
lines changed

src/swift/Data.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,13 @@ public struct DispatchData : RandomAccessCollection {
9191
public func enumerateBytes(
9292
block: @noescape (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
9393
{
94-
_swift_dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in
94+
// FIXME: When SR-2313 (withoutActuallyEscaping) is implemented, use it to replace unsafeBitCast
95+
let nonEscapingBlock = unsafeBitCast(block, to: _enumerateBytesBlock.self)
96+
_ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in
9597
let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size)
9698
let bp = UnsafeBufferPointer(start: bytePtr, count: size)
9799
var stop = false
98-
block(bp, offset, &stop)
100+
nonEscapingBlock(bp, offset, &stop)
99101
return !stop
100102
}
101103
}
@@ -274,10 +276,7 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence {
274276
internal var _position: DispatchData.Index
275277
}
276278

277-
typealias _swift_data_applier = @convention(block) (dispatch_data_t, Int, UnsafeRawPointer, Int) -> Bool
278-
279-
@_silgen_name("_swift_dispatch_data_apply")
280-
internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier)
279+
typealias _enumerateBytesBlock = (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void
281280

282281
@_silgen_name("_swift_dispatch_data_empty")
283282
internal func _swift_dispatch_data_empty() -> dispatch_data_t

src/swift/DispatchStubs.cc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,6 @@ _swift_dispatch_block_testcancel(dispatch_block_t block) {
141141
return dispatch_block_testcancel(block);
142142
}
143143

144-
SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE
145-
extern "C" bool
146-
_swift_dispatch_data_apply(dispatch_data_t data, bool (^applier)(dispatch_data_t, size_t, const void *, size_t)) {
147-
return dispatch_data_apply(data, applier);
148-
}
149-
150144
SWIFT_CC(swift) DISPATCH_RUNTIME_STDLIB_INTERFACE
151145
extern "C" void
152146
_swift_dispatch_async(dispatch_queue_t queue, dispatch_block_t block) {

0 commit comments

Comments
 (0)