From da17c26bae5a8604990ba49426765cab7496882d Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 22 Sep 2025 18:48:16 +0200 Subject: [PATCH] fix handling of large indices in SmallProjectionPath * Fix the right shift operator which didn't work if the number of bits is exactly 64 * Detect overflow when combining indices Such large indices usually don't appear in real code, except in internal String operations where (potentially large) integer values are treated as pointers. Fixes a compiler crash https://github.com/swiftlang/swift/issues/84372 rdar://160863199 --- .../SIL/Utilities/SmallProjectionPath.swift | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/SmallProjectionPath.swift b/SwiftCompilerSources/Sources/SIL/Utilities/SmallProjectionPath.swift index cfb206bd27f66..a6c9ed7156e39 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/SmallProjectionPath.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/SmallProjectionPath.swift @@ -190,7 +190,7 @@ public struct SmallProjectionPath : Hashable, CustomStringConvertible, NoReflect /// Pops \p numBits from the path. private func pop(numBits: Int) -> SmallProjectionPath { - return Self(bytes: bytes &>> numBits) + return Self(bytes: bytes >> numBits) } /// Pops and returns the first path component included the resulting path @@ -214,7 +214,7 @@ public struct SmallProjectionPath : Hashable, CustomStringConvertible, NoReflect // Ignore zero indices return self } - if k == .indexedElement { + if k == .indexedElement && index &+ i >= 0 { // "Merge" two constant successive indexed elements return pop(numBits: numBits).push(.indexedElement, index: index + i) } @@ -691,7 +691,8 @@ extension SmallProjectionPath { overlapping() predicates() path2path() - + indexedElements() + func basicPushPop() { let p1 = SmallProjectionPath(.structField, index: 3) .push(.classField, index: 12345678) @@ -964,5 +965,23 @@ extension SmallProjectionPath { assert(result == nil) } } + + func indexedElements() { + let p1 = SmallProjectionPath(.indexedElement, index: 1) + let (k1, i1, s1) = p1.pop() + assert(k1 == .indexedElement && i1 == 1 && s1.isEmpty) + + let p2 = SmallProjectionPath(.indexedElement, index: -1) + let (k2, _, s2) = p2.pop() + assert(k2 == .anything && s2.isEmpty) + + let p3 = SmallProjectionPath(.indexedElement, index: 0xfffffffffffff) + let (k3, i3, s3) = p3.pop() + assert(k3 == .indexedElement && i3 == 0xfffffffffffff && s3.isEmpty) + + let p4 = p3.push(.indexedElement, index: Int.max) + let (k4, _, s4) = p4.pop() + assert(k4 == .anyIndexedElement && s4.isEmpty) + } } }