Skip to content

Commit 928900c

Browse files
committed
Fix Unmanaged.passRetained
Unmanaged.passRetained was originally implemented as: - store the passed referenced into an unowned(unsafe) reference - (the reference will now be released if the store is the last use) - reload the unowned(unsafe) reference - retain the reloaded reference It should be implemented as: - retain the passed reference - store the passed reference to an unowned(unsafe) reference Fixes rdar://105609600 (🔥 non-deterministic miscompile in stdlib's _StringGuts.populateBreadcrumbs)
1 parent bfd140f commit 928900c

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

stdlib/public/core/Unmanaged.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ public struct Unmanaged<Instance: AnyObject> {
6464
/// - Returns: An unmanaged reference to the object passed as `value`.
6565
@_transparent
6666
public static func passRetained(_ value: Instance) -> Unmanaged {
67-
return Unmanaged(_private: value).retain()
67+
// Retain 'value' before it becomes unmanaged. This may be its last use.
68+
Builtin.retain(value)
69+
return Unmanaged(_private: value)
6870
}
6971

7072
/// Creates an unmanaged reference without performing an unbalanced
@@ -219,6 +221,11 @@ public struct Unmanaged<Instance: AnyObject> {
219221
}
220222

221223
/// Performs an unbalanced retain of the object.
224+
///
225+
/// Note: Use Umanaged.passRetained(object) instead to ensure that
226+
/// the reference to object is retained before it becomes
227+
/// unmanaged. Once a reference is unmanaged, its underlying object
228+
/// may be freed by the system.
222229
@_transparent
223230
public func retain() -> Unmanaged {
224231
Builtin.retain(_value)

0 commit comments

Comments
 (0)