Skip to content

Commit 6f9edc8

Browse files
committed
[stdlib] String.UnicodeScalarView: Fix some index validation issues
`String.UnicodeScalarView` currently lacks proper index validation in its `index(after:)` and `index(before:)` methods, leading to out-of-bounds memory accesses when index navigation methods in this view are given invalid indices. (Also see swiftlang#41598 and swiftlang#41417) rdar://89498541
1 parent 922201e commit 6f9edc8

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

stdlib/public/core/StringUnicodeScalarView.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,11 @@ extension String.UnicodeScalarView: BidirectionalCollection {
106106
/// - Precondition: The next location exists.
107107
@inlinable @inline(__always)
108108
public func index(after i: Index) -> Index {
109-
let i = _guts.scalarAlign(i)
110-
_internalInvariant(i < endIndex)
111109
// TODO(String performance): isASCII fast-path
112110

111+
_precondition(i < endIndex, "String index is out of bounds")
112+
let i = _guts.scalarAlign(i)
113+
113114
if _fastPath(_guts.isFastUTF8) {
114115
let len = _guts.fastUTF8ScalarLength(startingAt: i._encodedOffset)
115116
return i.encoded(offsetBy: len)._scalarAligned
@@ -128,10 +129,16 @@ extension String.UnicodeScalarView: BidirectionalCollection {
128129
/// - Precondition: The previous location exists.
129130
@inlinable @inline(__always)
130131
public func index(before i: Index) -> Index {
131-
let i = _guts.scalarAlign(i)
132-
_precondition(i._encodedOffset > 0)
133132
// TODO(String performance): isASCII fast-path
134133

134+
// Note: bounds checking in `index(before:)` is tricky as scalar aligning an
135+
// index may need to access storage, but it may also move it closer towards
136+
// the `startIndex`. Therefore, we must check against the `endIndex` before
137+
// aligning, but we need to delay the `i > startIndex` check until after.
138+
_precondition(i <= endIndex, "String index is out of bounds")
139+
let i = _guts.scalarAlign(i)
140+
_precondition(i > startIndex, "String index is out of bounds")
141+
135142
if _fastPath(_guts.isFastUTF8) {
136143
let len = _guts.withFastUTF8 { utf8 -> Int in
137144
return _utf8ScalarLength(utf8, endingAt: i._encodedOffset)

0 commit comments

Comments
 (0)