Merge pull request #12775 from jckarter/key-path-optional-chain-out-of-bounds-4.0
[4.0] KeyPath: Fix out-of-bounds access when instantiating keypaths with optional chaining components.
diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift
index 61e0a4d..faeccdd 100644
--- a/stdlib/public/core/KeyPath.swift
+++ b/stdlib/public/core/KeyPath.swift
@@ -1915,13 +1915,14 @@
// Scan the pattern to figure out the dynamic capability of the key path.
// Start off assuming the key path is writable.
var capability: KeyPathKind = .value
+ var didChain = false
let bufferPtr = pattern.advanced(by: keyPathObjectHeaderSize)
var buffer = KeyPathBuffer(base: bufferPtr)
var size = buffer.data.count + MemoryLayout<Int>.size
var alignmentMask = MemoryLayout<Int>.alignment - 1
- scanComponents: while true {
+ while true {
let header = buffer.pop(RawKeyPathComponent.Header.self)
func popOffset() {
@@ -2006,8 +2007,8 @@
case .optionalChain,
.optionalWrap:
// Chaining always renders the whole key path read-only.
- capability = .readOnly
- break scanComponents
+ didChain = true
+ break
case .optionalForce:
// No effect.
@@ -2022,6 +2023,11 @@
alignment: MemoryLayout<Int>.alignment)
}
+ // Chaining always renders the whole key path read-only.
+ if didChain {
+ capability = .readOnly
+ }
+
// Grab the class object for the key path type we'll end up with.
func openRoot<Root>(_: Root.Type) -> AnyKeyPath.Type {
func openLeaf<Leaf>(_: Leaf.Type) -> AnyKeyPath.Type {
diff --git a/test/stdlib/KeyPath.swift b/test/stdlib/KeyPath.swift
index b1fb84d..5d5182b 100644
--- a/test/stdlib/KeyPath.swift
+++ b/test/stdlib/KeyPath.swift
@@ -666,5 +666,25 @@
expectEqual(base[keyPath: ints_be], (17 + 38).bigEndian)
}
+// SR-6096
+
+protocol Protocol6096 {}
+struct Value6096<ValueType> {}
+extension Protocol6096 {
+ var asString: String? {
+ return self as? String
+ }
+}
+extension Value6096 where ValueType: Protocol6096 {
+ func doSomething() {
+ _ = \ValueType.asString?.endIndex
+ }
+}
+extension Int: Protocol6096 {}
+
+keyPath.test("optional chaining component that needs generic instantiation") {
+ Value6096<Int>().doSomething()
+}
+
runAllTests()