-
Unsafe Swift
What exactly makes code “unsafe”? Join the Swift team as we take a look at the programming language's safety precautions — and when you might need to reach for unsafe operations. We'll take a look at APIs that can cause unexpected states if not used correctly, and how you can write code more specifically to avoid undefined behavior. Learn how to work with C APIs that use pointers and the steps to take when you want to use Swift's unsafe pointer APIs.
To get the most out of this session, you should have some familiarity with Swift and the C programming language. And for more information on working with pointers, check out "Safely Manage Pointers in Swift".Ressources
Vidéos connexes
WWDC20
WWDC16
-
Rechercher dans cette vidéo…
-
-
0:52 - Optional's force unwrapping operator
let value: Int? = nil print(value!) // Fatal error: Unexpectedly found nil while unwrapping an Optional value -
1:58 - Unsafe force-unwrapping
let value: String? = "Hello" print(value.unsafelyUnwrapped) // Hello -
2:25 - Invalid use of unsafe force-unwrapping
let value: String? = nil print(value.unsafelyUnwrapped) // ?! -
4:23 - Invalid use of unsafe force-unwrapping
let value: String? = nil print(value.unsafelyUnwrapped) // Guaranteed fatal error in debug builds -
7:37 - Manual memory management
let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1) ptr.initialize(to: 42) print(ptr.pointee) // 42 ptr.deallocate() ptr.pointee = 23 // UNDEFINED BEHAVIOR -
10:04 - Passing an array of integers to a C function (1)
void process_integers(const int *start, size_t count); -
10:08 - Passing an array of integers to a C function (2)
func process_integers(_ start: UnsafePointer<CInt>!, _ count: Int) -
10:17 - Passing an array of integers to a C function (3)
let start = UnsafeMutablePointer<CInt>.allocate(capacity: 4) start.initialize(to: 0) (start + 1).initialize(to: 2) (start + 2).initialize(to: 4) (start + 3).initialize(to: 6) process_integers(start, 4) start.deinitialize(count: 4) start.deallocate() -
12:33 - Unsafe buffer pointer types
UnsafeBufferPointer<Element> UnsafeMutableBufferPointer<Element> UnsafeRawBufferPointer UnsafeMutableRawBufferPointer -
13:28 - Accessing contiguous collection storage
Sequence.withContiguousStorageIfAvailable(_:) MutableCollection.withContiguousMutableStorageIfAvailable(_:) String.withCString(_:) String.withUTF8(_:) Array.withUnsafeBytes(_:) Array.withUnsafeBufferPointer(_:) Array.withUnsafeMutableBytes(_:) Array.withUnsafeMutableBufferPointer(_:) -
13:39 - Temporary pointers to Swift values
withUnsafePointer(to:_:) withUnsafeMutablePointer(to:_:) withUnsafeBytes(of:_:) withUnsafeMutableBytes(of:_:) -
13:48 - Passing an array of integers to a C function (4)
let values: [CInt] = [0, 2, 4, 6] values.withUnsafeBufferPointer { buffer in print_integers(buffer.baseAddress!, buffer.count) } -
14:25 - Passing an array of integers to a C function (5)
let values: [CInt] = [0, 2, 4, 6] print_integers(values, values.count) -
15:36 - Advanced C interoperability
func sysctl( _ name: UnsafeMutablePointer<CInt>!, _ namelen: CUnsignedInt, _ oldp: UnsafeMutableRawPointer!, _ oldlenp: UnsafeMutablePointer<Int>!, _ newp: UnsafeMutableRawPointer!, _ newlen: Int ) -> CInt -
16:32 - Advanced C interoperability
import Darwin func cachelineSize() -> Int { var query = [CTL_HW, HW_CACHELINE] var result: CInt = 0 var resultSize = MemoryLayout<CInt>.size let r = sysctl(&query, CUnsignedInt(query.count), &result, &resultSize, nil, 0) precondition(r == 0, "Cannot query cache line size") precondition(resultSize == MemoryLayout<CInt>.size) return Int(result) } print(cachelineSize()) // 64 -
18:18 - Advanced C interoperability
import Darwin func cachelineSize() -> Int { var query = [CTL_HW, HW_CACHELINE] return query.withUnsafeMutableBufferPointer { buffer in var result: CInt = 0 withUnsafeMutablePointer(to: &result) { resultptr in var resultSize = MemoryLayout<CInt>.size let r = withUnsafeMutablePointer(to: &resultSize) { sizeptr in sysctl(buffer.baseAddress, CUnsignedInt(buffer.count), resultptr, sizeptr, nil, 0) } precondition(r == 0, "Cannot query cache line size") precondition(resultSize == MemoryLayout<CInt>.size) } return Int(result) } } print(cachelineSize()) // 64 -
18:30 - Advanced C interoperability
import Darwin func cachelineSize() -> Int { var query = [CTL_HW, HW_CACHELINE] var result: CInt = 0 var resultSize = MemoryLayout<CInt>.size let r = sysctl(&query, CUnsignedInt(query.count), &result, &resultSize, nil, 0) precondition(r == 0, "Cannot query cache line size") precondition(resultSize == MemoryLayout<CInt>.size) return Int(result) } print(cachelineSize()) // 64 -
18:48 - Closure-based vs. implicit pointers
var value = 42 withUnsafeMutablePointer(to: &value) { p in p.pointee += 1 } print(value) // 43 -
19:19 - Closure-based vs. implicit pointers
var value = 42 withUnsafeMutablePointer(to: &value) { p in p.pointee += 1 } print(value) // 43 var value2 = 42 let p = UnsafeMutablePointer(&value2) // BROKEN -- dangling pointer! p.pointee += 1 print(value2) -
19:43 - Initializing contiguous collection storage
Array.init(unsafeUninitializedCapacity:initializingWith:) String.init(unsafeUninitializedCapacity:initializingUTF8With:) -
20:02 - Initializing a String value using a C function
import Darwin func kernelVersion() -> String { var query = [CTL_KERN, KERN_VERSION] var length = 0 let r = sysctl(&query, 2, nil, &length, nil, 0) precondition(r == 0, "Error retrieving kern.version") return String(unsafeUninitializedCapacity: length) { buffer in var length = buffer.count let r = sysctl(&query, 2, buffer.baseAddress, &length, nil, 0) precondition(r == 0, "Error retrieving kern.version") precondition(length > 0 && length <= buffer.count) precondition(buffer[length - 1] == 0) return length - 1 } } print(kernelVersion()) // Darwin Kernel Version 19.5.0: Thu Apr 30 18:25:59 PDT 2020; root:xnu-6153.121.1~7/RELEASE_X86_64
-