Skip to content

Commit 2a78475

Browse files
authored
Stop at end of search string in TwoWaySearcher (#631)
When searching for a substring that doesn't exist, it was possible for TwoWaySearcher to advance beyond the end of the search string, causing a crash. This change adds a `limitedBy:` parameter to that index movement, avoiding the invalid movement. Fixes rdar://105154010
1 parent 8184fc0 commit 2a78475

File tree

2 files changed

+14
-1
lines changed

2 files changed

+14
-1
lines changed

Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ extension TwoWaySearcher: CollectionSearcher {
133133
searched.formIndex(before: &lIndex)
134134

135135
if pattern[i] != searched[lIndex] {
136-
searched.formIndex(&state.criticalIndex, offsetBy: period)
136+
_ = searched.formIndex(
137+
&state.criticalIndex,
138+
offsetBy: period,
139+
limitedBy: searched.endIndex)
137140
if periodIsExact { state.memory = (pattern.count - period, end) }
138141
return nil
139142
}

Tests/RegexTests/AlgorithmsTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,16 @@ class AlgorithmTests: XCTestCase {
174174
expectRanges("ababacabababa", "abababa", [6..<13])
175175
expectRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13])
176176
}
177+
178+
// rdar://105154010
179+
func testFirstRangeMissingCrash() {
180+
let str = "%2$@ %#@AROUND_TIME@"
181+
let target = "%@"
182+
XCTAssertNil(str.firstRange(of: target))
183+
XCTAssertNil(str.dropFirst().dropLast().firstRange(of: target))
184+
XCTAssertNil(str.dropFirst().dropLast().firstRange(of: target[...]))
185+
XCTAssertNil(str.firstRange(of: target[...]))
186+
}
177187

178188
func testRegexSplit() {
179189
func expectSplit(

0 commit comments

Comments
 (0)