mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
It causes a use-after-free problem with more aggressive destroy hoisting in the compiler. Also replace tabs with spaces in this file.
387 lines
12 KiB
Swift
387 lines
12 KiB
Swift
// RUN: %empty-directory(%t)
|
|
// RUN: %target-build-swift -swift-version 4 %s %import-libdispatch -o %t/a.out-4 && %target-codesign %t/a.out-4 && %target-run %t/a.out-4
|
|
// RUN: %target-build-swift -swift-version 4.2 %s %import-libdispatch -o %t/a.out-4.2 && %target-codesign %t/a.out-4.2 && %target-run %t/a.out-4.2
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: libdispatch
|
|
|
|
import Dispatch
|
|
import StdlibUnittest
|
|
|
|
defer { runAllTests() }
|
|
|
|
var DispatchAPI = TestSuite("DispatchAPI")
|
|
|
|
DispatchAPI.test("dispatch_data_t enumeration") {
|
|
// Ensure we can iterate the empty iterator
|
|
for _ in DispatchData.empty {
|
|
_ = 1
|
|
}
|
|
}
|
|
|
|
DispatchAPI.test("dispatch_data_t deallocator") {
|
|
let q = DispatchQueue(label: "dealloc queue")
|
|
var t = 0
|
|
|
|
do {
|
|
let size = 1024
|
|
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
|
|
let _ = DispatchData(bytesNoCopy: UnsafeBufferPointer(start: p, count: size), deallocator: .custom(q, {
|
|
t = 1
|
|
p.deallocate();
|
|
}))
|
|
}
|
|
|
|
q.sync {
|
|
expectEqual(1, t)
|
|
}
|
|
}
|
|
|
|
DispatchAPI.test("DispatchData.copyBytes") {
|
|
let source1: [UInt8] = [0, 1, 2, 3]
|
|
var dest: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
|
|
|
|
var dispatchData = source1.withUnsafeBytes { return DispatchData(bytes: $0) }
|
|
|
|
dest.withContiguousMutableStorageIfAvailable { destPtr in
|
|
// Copy from offset 0
|
|
var count = dispatchData.copyBytes(to: destPtr, from: 0..<2)
|
|
expectEqual(count, 2)
|
|
expectEqual(destPtr[0], 0)
|
|
expectEqual(destPtr[1], 1)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 2
|
|
count = dispatchData.copyBytes(to: destPtr, from: 2..<4)
|
|
expectEqual(count, 2)
|
|
expectEqual(destPtr[0], 2)
|
|
expectEqual(destPtr[1], 3)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Add two more regions
|
|
let source2: [UInt8] = [0x10, 0x11, 0x12, 0x13]
|
|
source2.withUnsafeBytes { dispatchData.append(DispatchData(bytes: $0)) }
|
|
|
|
let source3: [UInt8] = [0x14, 0x15, 0x16]
|
|
source3.withUnsafeBytes { dispatchData.append(DispatchData(bytes: $0)) }
|
|
|
|
// Copy from offset 0. Copies across the first two regions
|
|
count = dispatchData.copyBytes(to: destPtr, from: 0..<6)
|
|
expectEqual(count, 6)
|
|
expectEqual(destPtr[0], 0)
|
|
expectEqual(destPtr[1], 1)
|
|
expectEqual(destPtr[2], 2)
|
|
expectEqual(destPtr[3], 3)
|
|
expectEqual(destPtr[4], 0x10)
|
|
expectEqual(destPtr[5], 0x11)
|
|
|
|
// Copy from offset 2. Copies across the first two regions
|
|
count = dispatchData.copyBytes(to: destPtr, from: 2..<8)
|
|
expectEqual(count, 6)
|
|
expectEqual(destPtr[0], 2)
|
|
expectEqual(destPtr[1], 3)
|
|
expectEqual(destPtr[2], 0x10)
|
|
expectEqual(destPtr[3], 0x11)
|
|
expectEqual(destPtr[4], 0x12)
|
|
expectEqual(destPtr[5], 0x13)
|
|
|
|
// Copy from offset 3. Copies across all three regions
|
|
count = dispatchData.copyBytes(to: destPtr, from: 3..<9)
|
|
expectEqual(count, 6)
|
|
expectEqual(destPtr[0], 3)
|
|
expectEqual(destPtr[1], 0x10)
|
|
expectEqual(destPtr[2], 0x11)
|
|
expectEqual(destPtr[3], 0x12)
|
|
expectEqual(destPtr[4], 0x13)
|
|
expectEqual(destPtr[5], 0x14)
|
|
|
|
// Copy from offset 5. Skips the first region and the first byte of the second
|
|
count = dispatchData.copyBytes(to: destPtr, from: 5..<11)
|
|
expectEqual(count, 6)
|
|
expectEqual(destPtr[0], 0x11)
|
|
expectEqual(destPtr[1], 0x12)
|
|
expectEqual(destPtr[2], 0x13)
|
|
expectEqual(destPtr[3], 0x14)
|
|
expectEqual(destPtr[4], 0x15)
|
|
expectEqual(destPtr[5], 0x16)
|
|
|
|
// Copy from offset 8. Skips the first two regions
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
count = dispatchData.copyBytes(to: destPtr, from: 8..<11)
|
|
expectEqual(count, 3)
|
|
expectEqual(destPtr[0], 0x14)
|
|
expectEqual(destPtr[1], 0x15)
|
|
expectEqual(destPtr[2], 0x16)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 9. Skips the first two regions and the first byte of the third
|
|
destPtr[2] = 0xFF
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
count = dispatchData.copyBytes(to: destPtr, from: 9..<11)
|
|
expectEqual(count, 2)
|
|
expectEqual(destPtr[0], 0x15)
|
|
expectEqual(destPtr[1], 0x16)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 9, but only 1 byte. Ends before the end of the data
|
|
destPtr[1] = 0xFF
|
|
destPtr[2] = 0xFF
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
count = dispatchData.copyBytes(to: destPtr, from: 9..<10)
|
|
expectEqual(count, 1)
|
|
expectEqual(destPtr[0], 0x15)
|
|
expectEqual(destPtr[1], 0xFF)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 2, but only 1 byte. This copy is bounded within the
|
|
// first region.
|
|
destPtr[1] = 0xFF
|
|
destPtr[2] = 0xFF
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
count = dispatchData.copyBytes(to: destPtr, from: 2..<3)
|
|
expectEqual(count, 1)
|
|
expectEqual(destPtr[0], 2)
|
|
expectEqual(destPtr[1], 0xFF)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
}
|
|
}
|
|
|
|
DispatchAPI.test("DispatchData.copyBytesUnsafeRawBufferPointer") {
|
|
let source1: [UInt8] = [0, 1, 2, 3]
|
|
|
|
var dest: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
|
|
var dispatchData = source1.withUnsafeBytes { return DispatchData(bytes: $0) }
|
|
|
|
dest.withContiguousMutableStorageIfAvailable { destPtr in
|
|
// Copy from offset 0
|
|
dispatchData.copyBytes(to: destPtr, from: 0..<2)
|
|
expectEqual(destPtr[0], 0)
|
|
expectEqual(destPtr[1], 1)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 2
|
|
dispatchData.copyBytes(to: destPtr, from: 2..<4)
|
|
expectEqual(destPtr[0], 2)
|
|
expectEqual(destPtr[1], 3)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Add two more regions
|
|
let source2: [UInt8] = [0x10, 0x11, 0x12, 0x13]
|
|
source2.withUnsafeBytes { dispatchData.append(DispatchData(bytes: $0)) }
|
|
|
|
let source3: [UInt8] = [0x14, 0x15, 0x16]
|
|
source3.withUnsafeBytes { dispatchData.append(DispatchData(bytes: $0)) }
|
|
|
|
// Copy from offset 0. Copies across the first two regions
|
|
dispatchData.copyBytes(to: destPtr, from: 0..<6)
|
|
expectEqual(destPtr[0], 0)
|
|
expectEqual(destPtr[1], 1)
|
|
expectEqual(destPtr[2], 2)
|
|
expectEqual(destPtr[3], 3)
|
|
expectEqual(destPtr[4], 0x10)
|
|
expectEqual(destPtr[5], 0x11)
|
|
|
|
// Copy from offset 2. Copies across the first two regions
|
|
dispatchData.copyBytes(to: destPtr, from: 2..<8)
|
|
expectEqual(destPtr[0], 2)
|
|
expectEqual(destPtr[1], 3)
|
|
expectEqual(destPtr[2], 0x10)
|
|
expectEqual(destPtr[3], 0x11)
|
|
expectEqual(destPtr[4], 0x12)
|
|
expectEqual(destPtr[5], 0x13)
|
|
|
|
// Copy from offset 3. Copies across all three regions
|
|
dispatchData.copyBytes(to: destPtr, from: 3..<9)
|
|
expectEqual(destPtr[0], 3)
|
|
expectEqual(destPtr[1], 0x10)
|
|
expectEqual(destPtr[2], 0x11)
|
|
expectEqual(destPtr[3], 0x12)
|
|
expectEqual(destPtr[4], 0x13)
|
|
expectEqual(destPtr[5], 0x14)
|
|
|
|
// Copy from offset 5. Skips the first region and the first byte of the second
|
|
dispatchData.copyBytes(to: destPtr, from: 5..<11)
|
|
expectEqual(destPtr[0], 0x11)
|
|
expectEqual(destPtr[1], 0x12)
|
|
expectEqual(destPtr[2], 0x13)
|
|
expectEqual(destPtr[3], 0x14)
|
|
expectEqual(destPtr[4], 0x15)
|
|
expectEqual(destPtr[5], 0x16)
|
|
|
|
// Copy from offset 8. Skips the first two regions
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
dispatchData.copyBytes(to: destPtr, from: 8..<11)
|
|
expectEqual(destPtr[0], 0x14)
|
|
expectEqual(destPtr[1], 0x15)
|
|
expectEqual(destPtr[2], 0x16)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 9. Skips the first two regions and the first byte of the third
|
|
destPtr[2] = 0xFF
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
dispatchData.copyBytes(to: destPtr, from: 9..<11)
|
|
expectEqual(destPtr[0], 0x15)
|
|
expectEqual(destPtr[1], 0x16)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 9, but only 1 byte. Ends before the end of the data
|
|
destPtr[1] = 0xFF
|
|
destPtr[2] = 0xFF
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
dispatchData.copyBytes(to: destPtr, from: 9..<10)
|
|
expectEqual(destPtr[0], 0x15)
|
|
expectEqual(destPtr[1], 0xFF)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
|
|
// Copy from offset 2, but only 1 byte. This copy is bounded within the
|
|
// first region.
|
|
destPtr[1] = 0xFF
|
|
destPtr[2] = 0xFF
|
|
destPtr[3] = 0xFF
|
|
destPtr[4] = 0xFF
|
|
destPtr[5] = 0xFF
|
|
dispatchData.copyBytes(to: destPtr, from: 2..<3)
|
|
expectEqual(destPtr[0], 2)
|
|
expectEqual(destPtr[1], 0xFF)
|
|
expectEqual(destPtr[2], 0xFF)
|
|
expectEqual(destPtr[3], 0xFF)
|
|
expectEqual(destPtr[4], 0xFF)
|
|
expectEqual(destPtr[5], 0xFF)
|
|
}
|
|
}
|
|
|
|
DispatchAPI.test("DispatchData.buffers") {
|
|
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
|
|
var ptr = UnsafeBufferPointer<UInt8>(start: bytes, count: bytes.count)
|
|
var data = DispatchData(bytes: ptr)
|
|
expectEqual(bytes.count, data.count)
|
|
for i in 0..<data.count {
|
|
expectEqual(data[i], bytes[i])
|
|
}
|
|
|
|
data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
|
|
expectEqual(bytes.count, data.count)
|
|
for i in 0..<data.count {
|
|
expectEqual(data[i], bytes[i])
|
|
}
|
|
|
|
ptr = UnsafeBufferPointer<UInt8>(start: nil, count: 0)
|
|
data = DispatchData(bytes: ptr)
|
|
expectEqual(data.count, 0)
|
|
|
|
data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
|
|
expectEqual(data.count, 0)
|
|
}
|
|
|
|
DispatchAPI.test("DispatchData.bufferUnsafeRawBufferPointer") {
|
|
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
|
|
var ptr = UnsafeRawBufferPointer(start: bytes, count: bytes.count)
|
|
var data = DispatchData(bytes: ptr)
|
|
expectEqual(bytes.count, data.count)
|
|
for i in 0..<data.count {
|
|
expectEqual(data[i], bytes[i])
|
|
}
|
|
|
|
data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
|
|
expectEqual(bytes.count, data.count)
|
|
for i in 0..<data.count {
|
|
expectEqual(data[i], bytes[i])
|
|
}
|
|
|
|
ptr = UnsafeRawBufferPointer(start: nil, count: 0)
|
|
data = DispatchData(bytes: ptr)
|
|
expectEqual(data.count, 0)
|
|
|
|
data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
|
|
expectEqual(data.count, 0)
|
|
}
|
|
|
|
DispatchAPI.test("DispatchData.enumerateBytes") {
|
|
let count = 240
|
|
var bytes = [UInt8]()
|
|
for i in 0..<count {
|
|
bytes.append(UInt8(i))
|
|
}
|
|
let data = bytes.withUnsafeBytes { return DispatchData(bytes: $0) }
|
|
|
|
var nextIndex = 0
|
|
#if swift(>=4.2)
|
|
data.enumerateBytes({ ptr, offset, stop in
|
|
for i in 0..<ptr.count {
|
|
expectEqual(ptr[i + offset], UInt8(i + offset))
|
|
}
|
|
nextIndex = offset + ptr.count
|
|
})
|
|
#else
|
|
data.enumerateBytes(block: { ptr, offset, stop in
|
|
for i in 0..<ptr.count {
|
|
expectEqual(ptr[i + offset], UInt8(i + offset))
|
|
}
|
|
nextIndex = offset + ptr.count
|
|
})
|
|
#endif
|
|
expectEqual(nextIndex, data.count)
|
|
}
|
|
|
|
DispatchAPI.test("DispatchData.enumerateBytesTrailingClosure") {
|
|
let count = 240
|
|
var bytes = [UInt8]()
|
|
for i in 0..<count {
|
|
bytes.append(UInt8(i))
|
|
}
|
|
let data = bytes.withUnsafeBytes { return DispatchData(bytes: $0) }
|
|
|
|
var nextIndex = 0
|
|
data.enumerateBytes() { ptr, offset, stop in
|
|
for i in 0..<ptr.count {
|
|
expectEqual(ptr[i + offset], UInt8(i + offset))
|
|
}
|
|
nextIndex = offset + ptr.count
|
|
}
|
|
expectEqual(nextIndex, data.count)
|
|
}
|