Skip to content

Commit 56a5797

Browse files
committed
[libdispatch-data-fixes] Appending UnsafeBufferPointers to data is unsafe
* The buffer-pointer based init methods were passing the dispatch data default destructor in such a way that the @convention(block)-ness was lost. This leads to a thunk being passed to dispatch instead of NULL. Subsequently, dispatch would reference rather than copy the provided data. Fixes: SR-2050 (<rdar://problem/27293973>)
1 parent bb40547 commit 56a5797

File tree

4 files changed

+30
-9
lines changed

4 files changed

+30
-9
lines changed

apinotes/Dispatch.apinotes

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ Functions:
198198
AvailabilityMsg: 'Use DispatchWorkItem.isCancelled'
199199
# dispatch_data
200200
- Name: dispatch_data_create
201-
SwiftPrivate: true
201+
Availability: nonswift
202202
- Name: dispatch_data_get_size
203203
SwiftPrivate: true
204204
- Name: dispatch_data_apply

stdlib/public/SDK/Dispatch/Data.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import SwiftShims
14+
1315
public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
1416
public typealias Iterator = DispatchDataIterator
1517
public typealias Index = Int
@@ -43,8 +45,8 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
4345
/// - parameter bytes: A pointer to the memory. It will be copied.
4446
/// - parameter count: The number of bytes to copy.
4547
public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
46-
__wrapped = __dispatch_data_create(
47-
buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
48+
__wrapped = _swift_dispatch_data_create(
49+
buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default()) as! __DispatchData
4850
}
4951

5052
/// Initialize a `Data` without copying the bytes.
@@ -55,8 +57,8 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
5557
public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
5658
let (q, b) = deallocator._deallocator
5759

58-
__wrapped = __dispatch_data_create(
59-
bytes.baseAddress!, bytes.count, q, b)
60+
__wrapped = _swift_dispatch_data_create(
61+
bytes.baseAddress!, bytes.count, q, b) as! __DispatchData
6062
}
6163

6264
internal init(data: __DispatchData) {
@@ -93,15 +95,15 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
9395
/// - parameter bytes: A pointer to the bytes to copy in to the data.
9496
/// - parameter count: The number of bytes to copy.
9597
public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
96-
let data = __dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default())
98+
let data = _swift_dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default()) as! __DispatchData
9799
self.append(DispatchData(data: data))
98100
}
99101

100102
/// Append data to the data.
101103
///
102104
/// - parameter data: The data to append to this data.
103105
public mutating func append(_ other: DispatchData) {
104-
let data = __dispatch_data_create_concat(__wrapped, other as __DispatchData)
106+
let data = __dispatch_data_create_concat(__wrapped, other.__wrapped)
105107
__wrapped = data
106108
}
107109

@@ -239,13 +241,13 @@ public struct DispatchDataIterator : IteratorProtocol, Sequence {
239241
_data as __DispatchData, &ptr, &self._count)
240242
self._ptr = UnsafePointer(ptr)
241243
self._position = _data.startIndex
244+
245+
// The only time we expect a 'nil' pointer is when the data is empty.
242246
assert(self._ptr != nil || self._count == self._position)
243247
}
244248

245249
/// Advance to the next element and return it, or `nil` if no next
246250
/// element exists.
247-
///
248-
/// - Precondition: No preceding call to `self.next()` has returned `nil`.
249251
public mutating func next() -> DispatchData._Element? {
250252
if _position == _count { return nil }
251253
let element = _ptr[_position];

stdlib/public/SwiftShims/DispatchShims.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ void _swift_dispatch_apply_current(
9595
unsigned int iterations,
9696
void SWIFT_DISPATCH_NOESCAPE (^block)(long));
9797

98+
SWIFT_RUNTIME_STDLIB_INTERFACE
99+
__swift_shims_dispatch_data_t
100+
_swift_dispatch_data_create(
101+
const void *buffer,
102+
__swift_size_t size,
103+
__swift_shims_dispatch_queue_t queue,
104+
__swift_shims_dispatch_block_t destructor);
105+
98106
#ifdef __cplusplus
99107
}} // extern "C", namespace swift
100108
#endif

stdlib/public/stubs/DispatchShims.mm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,14 @@ void SWIFT_DISPATCH_NOESCAPE (^block)(long))
120120
block((long)i);
121121
});
122122
}
123+
124+
__swift_shims_dispatch_data_t
125+
swift::_swift_dispatch_data_create(
126+
const void *buffer,
127+
__swift_size_t size,
128+
__swift_shims_dispatch_queue_t queue,
129+
__swift_shims_dispatch_block_t destructor)
130+
{
131+
return dispatch_data_create(buffer, size, cast(queue), cast(destructor));
132+
}
133+

0 commit comments

Comments
 (0)