Skip to content

Commit 86467bb

Browse files
atricklorentey
authored andcommitted
Fix potentially undefined behavior in StringObject.nativeStorage
Speculatively fixing this to rule out potential miscompiles. The compiler needs to know if a reference is being materialized out of thin air. The proper way to do that is with the Unmanaged API. Under the hood, this forces the reference into an "unowned(unsafe)" variable which the reference must be reloaded from. That tells the compiler that it can't optimize some seemingly unrelated object which the reference may happen to refer to at runtime. /// Warning: Casting from an integer or a pointer type to a reference type /// is undefined behavior. It may result in incorrect code in any future /// compiler release. To convert a bit pattern to a reference type: /// 1. convert the bit pattern to an UnsafeRawPointer. /// 2. create an unmanaged reference using Unmanaged.fromOpaque() /// 3. obtain a managed reference using Unmanaged.takeUnretainedValue() /// The programmer must ensure that the resulting reference has already been /// manually retained.
1 parent 2e8ae40 commit 86467bb

File tree

2 files changed

+17
-5
lines changed

2 files changed

+17
-5
lines changed

stdlib/public/core/Builtin.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,23 @@ func _canBeClass<T>(_: T.Type) -> Int8 {
7272
/// `unsafeBitCast(_:to:)` with class or pointer types; doing so may
7373
/// introduce undefined behavior.
7474
///
75-
/// - Warning: Calling this function breaks the guarantees of the Swift type
76-
/// system; use with extreme care.
75+
/// Warning: Calling this function breaks the guarantees of the Swift type
76+
/// system; use with extreme care.
7777
///
78-
/// - Parameters:
78+
/// Warning: Casting from an integer or a pointer type to a reference type
79+
/// is undefined behavior. It may result in incorrect code in any future
80+
/// compiler release. To convert a bit pattern to a reference type:
81+
/// 1. convert the bit pattern to an UnsafeRawPointer.
82+
/// 2. create an unmanaged reference using Unmanaged.fromOpaque()
83+
/// 3. obtain a managed reference using Unmanaged.takeUnretainedValue()
84+
/// The programmer must ensure that the resulting reference has already been
85+
/// manually retained.
86+
///
87+
/// Parameters:
7988
/// - x: The instance to cast to `type`.
8089
/// - type: The type to cast `x` to. `type` and the type of `x` must have the
8190
/// same size of memory representation and compatible memory layout.
82-
/// - Returns: A new instance of type `U`, cast from `x`.
91+
/// Returns: A new instance of type `U`, cast from `x`.
8392
@inlinable // unsafe-performance
8493
@_transparent
8594
public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {

stdlib/public/core/StringObject.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,10 @@ extension _StringObject {
940940
return _unsafeUncheckedDowncast(storage, to: __StringStorage.self)
941941
#else
942942
_internalInvariant(hasNativeStorage)
943-
return Builtin.reinterpretCast(largeAddressBits)
943+
let storageAddress =
944+
UnsafeRawPointer(bitPattern:largeAddressBits)._unsafelyUnwrappedUnchecked
945+
let unmanagedRef = Unmanaged<__StringStorage>.fromOpaque(storageAddress)
946+
return unmanagedRef.takeUnretainedValue()
944947
#endif
945948
}
946949

0 commit comments

Comments
 (0)