You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: visions/memory-safety.md
+47-6Lines changed: 47 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -74,11 +74,53 @@ func memcpy(
74
74
75
75
The rules described above make it possible to detect and report the use of unsafe constructs in Swift.
76
76
77
-
An `@unsafe` function should be allowed to use other unsafe constructs without emitting any diagnostics. However, there are also library functions that encapsulate unsafe behavior in a safe API, such as the standard library’s `Array` and [`Span`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0447-span-access-shared-contiguous-storage.md)that are necessarily built from unsafe primitives. Such functions need some way to acknowledge the unsafe behavior while still being considered safe from the outside, such as an `unsafe { ... }` code block or a `@safe(unchecked)` attribute.
77
+
An `@unsafe` function is allowed to use other unsafe constructs. As such, a Swift module compiled in the strictly-safe subset can contain both safe and unsafe code, but all unsafe code is marked by `@unsafe`. A client of the module can opt to use only the safe parts of that module, potentially using the strict safety checking to ensure this.
78
+
79
+
### Wrapping unsafe behavior in safe APIs
80
+
81
+
There should also be a way to wrap unsafe behavior into safe APIs. For example, the standard library's `Array` and [`Span`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0447-span-access-shared-contiguous-storage.md) are necessarily implemented from unsafe primitives, such as `UnsafeRawPointer`, but expose primarily safe APIs. For example, the `Span` type could be defined like this:
The subscript operation is safe, but necessarily uses `buffer`, which has an `@unsafe` type. Its implementation must acknowledge that it is using unsafe constructs internally, but that it does so in a manner that preserves safety for clients. There are several potential syntaxes, including an `unsafe { ... }` code block, which could look like this:
90
+
91
+
```swift
92
+
publicsubscript(_position: Int) ->Element {
93
+
get {
94
+
unsafe {
95
+
precondition(position >=0&& position < buffer.count)
96
+
return buffer[position]
97
+
}
98
+
}
99
+
}
100
+
```
101
+
102
+
Alternatively, Swift could provide a `@safe(unchecked)` attribute that states that a particular API is safe, but that its safety cannot be checked by the compiler, akin to `@unchecked Sendable` conformances:
103
+
104
+
```swift
105
+
publicsubscript(_position: Int) ->Element {
106
+
@safe(unchecked) get {
107
+
precondition(position >=0&& position < buffer.count)
108
+
return buffer[position]
109
+
}
110
+
}
111
+
```
112
+
113
+
The specific syntax chosen will be the subject of a specific proposal, and need not be determined by this vision document. Regardless, a Swift module that enables strict safety checking must limit its use of unsafe constructs to `@unsafe` declarations or those parts of the code that have acknowledged local use of unsafe constructs.
114
+
115
+
### Auditability
116
+
117
+
The aim of optional strict memory safety for Swift is to make it possible to write Swift that avoids unintentional use of unsafe constructs while not preventing their use entirely. To aid projects that wish to set a higher bar for memory safety, such as permitting no unsafe constructs outside of the standard library or requiring additional code review for any uses of unsafe constructs, Swift tooling should provide a way to audit the uses of unsafe constructs within an entire project (including its dependencies). An auditing tool should be able to identify and report Swift modules that were compiled without strict memory safety as well as all of the places where the opt-out mechanism (e.g., `unsafe { ... }` blocks or `@safe(unchecked)`) is used in modules that do opt in to strict memory safety.
118
+
119
+
## Improving the expressibility of strictly-safe Swift
78
120
79
121
The following sections describe language features and library constructs that improve on what can be expressed within the strictly-safe subset of Swift. These improvements will also benefit Swift in general, making it easier to correctly work with contiguous memory and interoperate with APIs from the C-family on languages.
80
122
81
-
## Accessing contiguous memory
123
+
###Accessing contiguous memory
82
124
83
125
Nearly every “unsafe” language feature and standard library API described in the previous section already has safe counterparts in the language: safe concurrency patterns via actors and `Mutex` , safe casting via `as?` , runtime-checked access to optionals (via `!` ) and continuations (`withChecked(Throwing)Continuation` ), and so on.
84
126
@@ -99,7 +141,7 @@ print(span.first ?? 0)
99
141
100
142
[Lifetime dependencies](https://github.com/swiftlang/swift-evolution/pull/2305) can greatly improve the expressiveness of non-escaping types, making it possible to build more complex data structures while maintaining memory safety.
101
143
102
-
## Expressing memory-safe interfaces for the C family of languages
144
+
###Expressing memory-safe interfaces for the C family of languages
103
145
104
146
The C family of languages do not provide memory safety along any of the dimensions described in this document. As such, a Swift program that makes use of C APIs is never fully “memory safe” in the strict sense, because any C code called from Swift could undermine the memory safety guarantees Swift is trying to provide. Requiring that all such C code be rewritten in Swift would go against Swift’s general philosophy of incremental adoption into existing ecosystems. Therefore, this document proposes a different strategy: code written in Swift will be auditably memory-safe so long as the C APIs it uses follow reasonable conventions with respect to memory safety. As such, writing new code (or incrementally rewriting code from the C family) will not introduce new memory safety bugs, so that adopting Swift in an existing code base will incrementally improve on memory safety. This approach is complementary to any improvements made to memory safety within the C family of languages, such as [bounds-safety checks for C](https://clang.llvm.org/docs/BoundsSafety.html) or [C++ standard library hardening](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3471r0.html).
105
147
@@ -167,7 +209,7 @@ The result coudl be the following memory-safe Swift API:
C++ offers a number of further opportunities for improved safety by modeling lifetimes. For example, `std::vector<T>` has a `front()` method that returns a reference to the element at the front of the vector:
173
215
@@ -188,5 +230,4 @@ could be imported into Swift as:
0 commit comments