Skip to content

Commit af1a815

Browse files
authored
Guard against racy access to NSError.setUserInfoValueProvider. (#4280)
This API is documented in its headers to only allow being called once for a particular domain, so we have to make sure our check for an existing provider is synchronized with the setting. rdar://problem/27541751
1 parent 67008ae commit af1a815

File tree

2 files changed

+5
-2
lines changed

2 files changed

+5
-2
lines changed

stdlib/public/SDK/Foundation/NSError.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public extension Error {
136136
}
137137
}
138138

139+
internal let _errorDomainUserInfoProviderQueue = DispatchQueue(
140+
label: "SwiftFoundation._errorDomainUserInfoProviderQueue")
141+
139142
/// Retrieve the default userInfo dictionary for a given error.
140143
@_silgen_name("swift_Foundation_getErrorDefaultUserInfo")
141144
public func _swift_Foundation_getErrorDefaultUserInfo(_ error: Error)
@@ -149,7 +152,8 @@ public func _swift_Foundation_getErrorDefaultUserInfo(_ error: Error)
149152
// user-info value providers.
150153
let domain = error._domain
151154
if domain != NSCocoaErrorDomain {
152-
if NSError.userInfoValueProvider(forDomain: domain) == nil {
155+
_errorDomainUserInfoProviderQueue.sync {
156+
if NSError.userInfoValueProvider(forDomain: domain) != nil { return }
153157
NSError.setUserInfoValueProvider(forDomain: domain) { (nsError, key) in
154158
let error = nsError as Error
155159

validation-test/stdlib/ErrorProtocol.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// RUN: %target-run-simple-swift
22
// REQUIRES: executable_test
3-
// REQUIRES: rdar27541751
43
// REQUIRES: objc_interop
54

65
import SwiftPrivate

0 commit comments

Comments
 (0)