Skip to content

Commit 6e7202e

Browse files
authored
Merge pull request #23174 from lorentey/tacoma-narrows
2 parents 4d7d2ef + 300595e commit 6e7202e

File tree

5 files changed

+249
-17
lines changed

5 files changed

+249
-17
lines changed

stdlib/public/Darwin/Foundation/NSDictionary.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ extension Dictionary : _ObjectiveCBridgeable {
136136
to: T.Type
137137
) {
138138
for i in (0..<count).reversed() {
139-
let bridged = Swift._forceBridgeFromObjectiveC(buffer[i], T.self)
139+
let bridged = buffer[i] as! T
140140
_bridgeInitialize(index: i, of: buffer, to: bridged)
141141
}
142142
}
@@ -222,11 +222,9 @@ extension Dictionary : _ObjectiveCBridgeable {
222222
if keyStride < objectStride || valueStride < objectStride {
223223
var builder = _DictionaryBuilder<Key, Value>(count: d.count)
224224
d.enumerateKeysAndObjects({ (anyKey: Any, anyValue: Any, _) in
225-
let anyObjectKey = anyKey as AnyObject
226-
let anyObjectValue = anyValue as AnyObject
227225
builder.add(
228-
key: Swift._forceBridgeFromObjectiveC(anyObjectKey, Key.self),
229-
value: Swift._forceBridgeFromObjectiveC(anyObjectValue, Value.self))
226+
key: anyKey as! Key,
227+
value: anyValue as! Value)
230228
})
231229
result = builder.take()
232230
} else {

stdlib/public/Darwin/Foundation/NSSet.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,8 @@ extension Set : _ObjectiveCBridgeable {
7777
// Swift. See rdar://problem/35995647
7878
var set = Set(minimumCapacity: s.count)
7979
s.enumerateObjects({ (anyMember: Any, _) in
80-
let member = Swift._forceBridgeFromObjectiveC(
81-
anyMember as AnyObject, Element.self)
8280
// FIXME: Log a warning if `member` is already in the set.
83-
set.insert(member)
81+
set.insert(anyMember as! Element)
8482
})
8583
result = set
8684
return
@@ -90,8 +88,7 @@ extension Set : _ObjectiveCBridgeable {
9088
// an NSSet.
9189
var builder = _SetBuilder<Element>(count: s.count)
9290
s.enumerateObjects({ (anyMember: Any, _) in
93-
builder.add(member: Swift._forceBridgeFromObjectiveC(
94-
anyMember as AnyObject, Element.self))
91+
builder.add(member: anyMember as! Element)
9592
})
9693
result = builder.take()
9794
}

stdlib/public/runtime/Casting.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3023,14 +3023,17 @@ _bridgeNonVerbatimFromObjectiveC(
30233023
const_cast<void*>(swift_dynamicCastUnknownClass(sourceValue,
30243024
objectiveCType));
30253025

3026-
if (sourceValueAsObjectiveCType) {
3027-
// The type matches. _forceBridgeFromObjectiveC returns `Self`, so
3028-
// we can just return it directly.
3029-
bridgeWitness->forceBridgeFromObjectiveC(
3030-
static_cast<HeapObject*>(sourceValueAsObjectiveCType),
3031-
destValue, nativeType, nativeType, bridgeWitness);
3032-
return;
3026+
if (!sourceValueAsObjectiveCType) {
3027+
swift::swift_dynamicCastFailure(_swift_getClass(sourceValue),
3028+
objectiveCType);
30333029
}
3030+
3031+
// The type matches. _forceBridgeFromObjectiveC returns `Self`, so
3032+
// we can just return it directly.
3033+
bridgeWitness->forceBridgeFromObjectiveC(
3034+
static_cast<HeapObject*>(sourceValueAsObjectiveCType),
3035+
destValue, nativeType, nativeType, bridgeWitness);
3036+
return;
30343037
}
30353038

30363039
// Fail.

validation-test/stdlib/DictionaryTrapsObjC.swift

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,142 @@ DictionaryTraps.test("BridgedKeyIsNotNSCopyable2")
147147
nsd.mutableCopy()
148148
}
149149

150+
DictionaryTraps.test("ForcedNonverbatimBridge.StringKey")
151+
.skip(.custom(
152+
{ _isFastAssertConfiguration() },
153+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
154+
.crashOutputMatches("Could not cast value of type")
155+
.code {
156+
let d1: NSDictionary = [
157+
"Gordon" as NSString: NSObject(),
158+
"William" as NSString: NSObject(),
159+
"Katherine" as NSString: NSObject(),
160+
"Lynn" as NSString: NSObject(),
161+
"Brian" as NSString: NSObject(),
162+
1756 as NSNumber: NSObject()]
163+
164+
expectCrashLater()
165+
_ = d1 as! Dictionary<String, Any>
166+
}
167+
168+
DictionaryTraps.test("ForcedNonverbatimBridge.IntKey")
169+
.skip(.custom(
170+
{ _isFastAssertConfiguration() },
171+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
172+
.crashOutputMatches("Could not cast value of type")
173+
.code {
174+
175+
let d1: NSDictionary = [
176+
4 as NSNumber: NSObject(),
177+
8 as NSNumber: NSObject(),
178+
15 as NSNumber: NSObject(),
179+
16 as NSNumber: NSObject(),
180+
23 as NSNumber: NSObject(),
181+
42 as NSNumber: NSObject(),
182+
"John" as NSString: NSObject()]
183+
184+
expectCrashLater()
185+
_ = d1 as! Dictionary<Int, Any>
186+
}
187+
188+
DictionaryTraps.test("ForcedNonverbatimBridge.Value")
189+
.skip(.custom(
190+
{ _isFastAssertConfiguration() },
191+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
192+
.crashOutputMatches("Could not cast value of type")
193+
.code {
194+
195+
let d1: NSDictionary = [
196+
4 as NSNumber: "Jack" as NSString,
197+
8 as NSNumber: "Kate" as NSString,
198+
15 as NSNumber: "Hurley" as NSString,
199+
16 as NSNumber: "Sawyer" as NSString,
200+
23 as NSNumber: "John" as NSString,
201+
42 as NSNumber: NSObject()]
202+
203+
expectCrashLater()
204+
_ = d1 as! Dictionary<NSObject, String>
205+
}
206+
207+
208+
DictionaryTraps.test("ForcedVerbatimBridge.StringKey")
209+
.skip(.custom(
210+
{ _isFastAssertConfiguration() },
211+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
212+
.crashOutputMatches("Could not cast value of type")
213+
.code {
214+
let d1: NSDictionary = [
215+
"Gordon" as NSString: NSObject(),
216+
"William" as NSString: NSObject(),
217+
"Katherine" as NSString: NSObject(),
218+
"Lynn" as NSString: NSObject(),
219+
"Brian" as NSString: NSObject(),
220+
1756 as NSNumber: NSObject()]
221+
222+
// With the ObjC runtime, the verbatim downcast is O(1); it performs no
223+
// runtime checks.
224+
let d2 = d1 as! Dictionary<NSString, NSObject>
225+
// Element access goes through the bridged path and performs forced downcasts.
226+
// This is where the odd numeric value is caught.
227+
expectCrashLater()
228+
for (key, value) in d2 {
229+
_ = (key, value)
230+
}
231+
}
232+
233+
DictionaryTraps.test("ForcedVerbatimBridge.IntKey")
234+
.skip(.custom(
235+
{ _isFastAssertConfiguration() },
236+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
237+
.crashOutputMatches("Could not cast value of type")
238+
.code {
239+
240+
let d1: NSDictionary = [
241+
4 as NSNumber: NSObject(),
242+
8 as NSNumber: NSObject(),
243+
15 as NSNumber: NSObject(),
244+
16 as NSNumber: NSObject(),
245+
23 as NSNumber: NSObject(),
246+
42 as NSNumber: NSObject(),
247+
"John" as NSString: NSObject()]
248+
249+
// With the ObjC runtime, the verbatim downcast is O(1); it performs no
250+
// runtime checks.
251+
let d2 = d1 as! Dictionary<NSNumber, NSObject>
252+
// Element access goes through the bridged path and performs forced downcasts.
253+
// This is where the odd numeric value is caught.
254+
expectCrashLater()
255+
for (key, value) in d2 {
256+
_ = (key, value)
257+
}
258+
}
259+
260+
DictionaryTraps.test("ForcedVerbatimBridge.Value")
261+
.skip(.custom(
262+
{ _isFastAssertConfiguration() },
263+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
264+
.crashOutputMatches("Could not cast value of type")
265+
.code {
266+
267+
let d1: NSDictionary = [
268+
4 as NSNumber: "Jack" as NSString,
269+
8 as NSNumber: "Kate" as NSString,
270+
15 as NSNumber: "Hurley" as NSString,
271+
16 as NSNumber: "Sawyer" as NSString,
272+
23 as NSNumber: "John" as NSString,
273+
42 as NSNumber: NSObject()]
274+
275+
// With the ObjC runtime, the verbatim downcast is O(1); it performs no
276+
// runtime checks.
277+
let d2 = d1 as! Dictionary<NSObject, NSString>
278+
// Element access goes through the bridged path and performs forced downcasts.
279+
// This is where the odd numeric value is caught.
280+
expectCrashLater()
281+
for (key, value) in d2 {
282+
_ = (key, value)
283+
}
284+
}
285+
150286
DictionaryTraps.test("Downcast1") {
151287
let d: Dictionary<NSObject, NSObject> = [ TestObjCKeyTy(10): NSObject(),
152288
NSObject() : NSObject() ]

validation-test/stdlib/Set.swift

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4613,4 +4613,102 @@ SetTestSuite.test("IndexValidation.RemoveAt.AfterGrow") {
46134613
s.remove(at: i)
46144614
}
46154615

4616+
#if _runtime(_ObjC)
4617+
SetTestSuite.test("ForcedNonverbatimBridge.Trap.String")
4618+
.skip(.custom(
4619+
{ _isFastAssertConfiguration() },
4620+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
4621+
.crashOutputMatches("Could not cast value of type")
4622+
.code {
4623+
4624+
let s1: NSSet = [
4625+
"Gordon" as NSString,
4626+
"William" as NSString,
4627+
"Katherine" as NSString,
4628+
"Lynn" as NSString,
4629+
"Brian" as NSString,
4630+
1756 as NSNumber]
4631+
4632+
expectCrashLater()
4633+
_ = s1 as! Set<String>
4634+
}
4635+
#endif
4636+
4637+
#if _runtime(_ObjC)
4638+
SetTestSuite.test("ForcedNonverbatimBridge.Trap.Int")
4639+
.skip(.custom(
4640+
{ _isFastAssertConfiguration() },
4641+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
4642+
.crashOutputMatches("Could not cast value of type")
4643+
.code {
4644+
4645+
let s1: NSSet = [
4646+
4 as NSNumber,
4647+
8 as NSNumber,
4648+
15 as NSNumber,
4649+
16 as NSNumber,
4650+
23 as NSNumber,
4651+
42 as NSNumber,
4652+
"John" as NSString]
4653+
4654+
expectCrashLater()
4655+
_ = s1 as! Set<Int>
4656+
}
4657+
#endif
4658+
4659+
#if _runtime(_ObjC)
4660+
SetTestSuite.test("ForcedVerbatimBridge.Trap.NSString")
4661+
.skip(.custom(
4662+
{ _isFastAssertConfiguration() },
4663+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
4664+
.crashOutputMatches("Could not cast value of type")
4665+
.code {
4666+
4667+
let s1: NSSet = [
4668+
"Gordon" as NSString,
4669+
"William" as NSString,
4670+
"Katherine" as NSString,
4671+
"Lynn" as NSString,
4672+
"Brian" as NSString,
4673+
1756 as NSNumber]
4674+
4675+
// With the ObjC runtime, the verbatim downcast is O(1); it performs no
4676+
// runtime checks.
4677+
let s2 = s1 as! Set<NSString>
4678+
// Element access goes through the bridged path and performs forced downcasts.
4679+
// This is where the odd numeric value is caught.
4680+
expectCrashLater()
4681+
for string in s2 {
4682+
_ = string
4683+
}
4684+
}
4685+
#endif
4686+
4687+
#if _runtime(_ObjC)
4688+
SetTestSuite.test("ForcedVerbatimBridge.Trap.NSNumber")
4689+
.skip(.custom(
4690+
{ _isFastAssertConfiguration() },
4691+
reason: "this trap is not guaranteed to happen in -Ounchecked"))
4692+
.crashOutputMatches("Could not cast value of type")
4693+
.code {
4694+
let s1: NSSet = [
4695+
4 as NSNumber,
4696+
8 as NSNumber,
4697+
15 as NSNumber,
4698+
16 as NSNumber,
4699+
23 as NSNumber,
4700+
42 as NSNumber,
4701+
"John" as NSString]
4702+
// With the ObjC runtime, the verbatim downcast is O(1); it performs no
4703+
// runtime checks.
4704+
let s2 = s1 as! Set<NSNumber>
4705+
// Element access goes through the bridged path and performs forced downcasts.
4706+
// This is where the odd numeric value is caught.
4707+
expectCrashLater()
4708+
for string in s2 {
4709+
_ = string
4710+
}
4711+
}
4712+
#endif
4713+
46164714
runAllTests()

0 commit comments

Comments
 (0)