|
| 1 | +# Remove Sendable conformance from unsafe pointer types |
| 2 | + |
| 3 | +* Proposal: [SE-NNNN](NNNN-re.md) |
| 4 | +* Authors: [Andrew Trick](https://github.com/atrick), [Doug Gregor](https://github.com/DougGregor) |
| 5 | +* Review Manager: TBD |
| 6 | +* Status: **Awaiting review** |
| 7 | + |
| 8 | +* Implementation: [apple/swift#39218](https://github.com/apple/swift/pull/39218) |
| 9 | + |
| 10 | +## Introduction |
| 11 | + |
| 12 | +[SE-0302](0302-concurrent-value-and-concurrent-closures.md) introduced the `Sendable` protocol, including `Sendable` requirements for various language constructs, conformances of various standard library types to `Sendable`, and inference rules for non-public types to implicitly conform to `Sendable`. SE-0302 states that the unsafe pointer types conform to `Sendable`: |
| 13 | + |
| 14 | +> `Unsafe(Mutable)(Buffer)Pointer`: these generic types _unconditionally_ conform to the `Sendable` protocol. This means that an unsafe pointer to a non-Sendable value can potentially be used to share such values between concurrency domains. Unsafe pointer types provide fundamentally unsafe access to memory, and the programmer must be trusted to use them correctly; enforcing a strict safety rule for one narrow dimension of their otherwise completely unsafe use seems inconsistent with that design. |
| 15 | +
|
| 16 | +Experience with `Sendable` shows that this formulation is unnecessarily dangerous and has unexpected negative consequences for implicit conformance. |
| 17 | + |
| 18 | +Swift-evolution thread: [Discussion thread](https://forums.swift.org/t/unsafepointer-sendable-should-be-revoked/51926) |
| 19 | + |
| 20 | +## Motivation |
| 21 | + |
| 22 | +The role of `Sendable` is to prevent sharing reference-semantic types across actor or task boundaries. Unsafe pointers have reference semantics, and therefore should not be be `Sendable`. |
| 23 | + |
| 24 | +Unsafe pointers are unsafe in one primary way: it is the developer's responsibility to guarantee the lifetime of the memory referenced by the unsafe pointer. This is an intentional and explicit hole in Swift's memory safety story that has been around since the beginning. That well-understood form of unsafety should not be implicitly extended to allow pointers to be unsafely used in concurrent code. The concurrency diagnostics that prevent race conditions in other types with reference semantics should provide the same protection for pointers. |
| 25 | + |
| 26 | +Another problem with making the unsafe pointers `Sendable` is the second-order effect it has on value types that store unsafe pointers. Consider a wrapper struct around a resource: |
| 27 | + |
| 28 | +```swift |
| 29 | +struct FileHandle { // implicitly Sendable |
| 30 | + var stored: UnsafeMutablePointer<File> |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +The `FileHandle` type will be inferred to be `Sendable` because all of its instance storage is `Sendable`. Even if we accept that an `UnsafeMutablePointer` by itself can be `Sendable ` because the "unsafe" can now apply to concurrency safety as well (as was argued in SE-0302), that same argument does not hold for the `FileHandle` type. Removing the conformance of the unsafe pointer types to `Sendable` eliminates the potential for it to propagate out to otherwise-safe wrappers. |
| 35 | + |
| 36 | +## Proposed solution |
| 37 | + |
| 38 | +Remove the `Sendable` conformance introduced by SE-0302 for the following types: |
| 39 | + |
| 40 | +* `AutoreleasingUnsafeMutablePointer` |
| 41 | +* `OpaquePointer` |
| 42 | +* `CVaListPointer` |
| 43 | +* `Unsafe(Mutable)?(Raw)?(Buffer)?Pointer` |
| 44 | +* `Unsafe(Mutable)?(Raw)?BufferPointer.Iterator` |
| 45 | + |
| 46 | +## Source compatibility |
| 47 | + |
| 48 | +The removal of `Sendable` conformances from unsafe pointer types can break code that depends on those conformances. There are two mitigating factors here that make us feel comfortable doing so at this time. The first mitigating factor is that `Sendable` is only very recently introduced in Swift 5.5, and `Sendable` conformances aren't enforced in the Swift Concurrency model just yet. The second is that the staging in of `Sendable` checking in the compiler implies that missing `Sendable` conformances are treated as warnings, not errors, so there is a smooth transition path for any code that depended on this now-removed conformances. |
| 49 | + |
| 50 | +## Effect on ABI stability |
| 51 | + |
| 52 | +`Sendable` is a marker protocol, which was designed to have zero ABI impact. Therefore, this proposal itself should have no ABI impact, because adding and removing `Sendable` conformances is invisible to the ABI. |
| 53 | + |
| 54 | +## Effect on API resilience |
| 55 | + |
| 56 | +This proposal does not affect API resilience. |
| 57 | + |
| 58 | +## Alternatives considered |
| 59 | + |
| 60 | +Keep SE-0302 behavior. This would require explicit "non-Sendable" annotation of many important aggregate types that embed unsafe pointers. |
0 commit comments