Skip to content

Commit a2694fd

Browse files
committed
Unsafe buffer index manipulation is unsafe
Also mark @safe operations
1 parent 89d9a20 commit a2694fd

7 files changed

+44
-17
lines changed

stdlib/public/core/Array.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1737,7 +1737,7 @@ extension Array {
17371737

17381738
var it = IndexingIterator(_elements: self)
17391739
it._position = endIndex
1740-
return (it,buffer.index(buffer.startIndex, offsetBy: self.count))
1740+
return (it,unsafe buffer.index(buffer.startIndex, offsetBy: self.count))
17411741
}
17421742
}
17431743

stdlib/public/core/ArraySlice.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1317,7 +1317,7 @@ extension ArraySlice {
13171317

13181318
var it = IndexingIterator(_elements: self)
13191319
it._position = endIndex
1320-
return (it,buffer.index(buffer.startIndex, offsetBy: self.count))
1320+
return (it,unsafe buffer.index(buffer.startIndex, offsetBy: self.count))
13211321
}
13221322
}
13231323

stdlib/public/core/ContiguousArray.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ extension ContiguousArray {
12571257

12581258
var it = IndexingIterator(_elements: self)
12591259
it._position = endIndex
1260-
return (it,buffer.index(buffer.startIndex, offsetBy: self.count))
1260+
return (it,unsafe buffer.index(buffer.startIndex, offsetBy: self.count))
12611261
}
12621262
}
12631263

stdlib/public/core/StringCreate.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ extension String {
349349

350350
transcodingLoop:
351351
while true {
352-
switch parser.parseScalar(from: &input) {
352+
switch unsafe parser.parseScalar(from: &input) {
353353
case .valid(let s):
354354
let scalar = Encoding.decode(s)
355355
guard let utf8 = Unicode.UTF8.encode(scalar) else {

stdlib/public/core/StringUTF8Validation.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal func validateUTF8(_ buf: UnsafeBufferPointer<UInt8>) -> UTF8ValidationR
5252
var lastValidIndex = buf.startIndex
5353

5454
@inline(__always) func guaranteeIn(_ f: (UInt8) -> Bool) throws(UTF8ValidationError) {
55-
guard let cu = iter.next() else { throw UTF8ValidationError() }
55+
guard let cu = unsafe iter.next() else { throw UTF8ValidationError() }
5656
guard f(cu) else { throw UTF8ValidationError() }
5757
}
5858
@inline(__always) func guaranteeContinuation() throws(UTF8ValidationError) {
@@ -119,7 +119,7 @@ internal func validateUTF8(_ buf: UnsafeBufferPointer<UInt8>) -> UTF8ValidationR
119119

120120
do {
121121
var isASCII = true
122-
while let cu = iter.next() {
122+
while let cu = unsafe iter.next() {
123123
if UTF8.isASCII(cu) { lastValidIndex &+= 1; continue }
124124
isASCII = false
125125
if _slowPath(!_isUTF8MultiByteLeading(cu)) {

stdlib/public/core/StringUTF8View.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ extension String.UTF8View {
432432
}
433433

434434
let it = String().utf8.makeIterator()
435-
return (it, buffer.index(buffer.startIndex, offsetBy: written))
435+
return (it, unsafe buffer.index(buffer.startIndex, offsetBy: written))
436436
}
437437
}
438438

stdlib/public/core/UnsafeBufferPointer.swift.gyb

+37-10
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ public struct Unsafe${Mutable}BufferPointer<Element: ~Copyable>: Copyable {
3434

3535
@usableFromInline
3636
@_preInverseGenerics
37+
@safe
3738
let _position: Unsafe${Mutable}Pointer<Element>?
3839

3940
/// The number of elements in the buffer.
4041
///
4142
/// If the `baseAddress` of this buffer is `nil`, the count is zero. However,
4243
/// a buffer can have a `count` of zero even with a non-`nil` base address.
4344
@_preInverseGenerics
45+
@safe
4446
public let count: Int
4547

4648
// This works around _debugPrecondition() impacting the performance of
@@ -81,6 +83,7 @@ public struct Unsafe${Mutable}BufferPointer<Element: ~Copyable>: Copyable {
8183

8284
@inlinable // unsafe-performance
8385
@_preInverseGenerics
86+
@safe
8487
public init(_empty: ()) {
8588
_position = nil
8689
count = 0
@@ -105,6 +108,7 @@ public struct Unsafe${Mutable}BufferPointer<Element: ~Copyable>: Copyable {
105108
/// - Parameter other: The mutable buffer pointer to convert.
106109
@inlinable // unsafe-performance
107110
@_preInverseGenerics
111+
@safe
108112
public init(_ other: UnsafeMutableBufferPointer<Element>) {
109113
_position = UnsafePointer<Element>(other._position)
110114
count = other.count
@@ -139,6 +143,7 @@ extension UnsafeBufferPointer {
139143
@frozen // unsafe-performance
140144
public struct Iterator {
141145
@usableFromInline
146+
@unsafe
142147
internal var _position, _end: UnsafePointer<Element>?
143148

144149
@inlinable // unsafe-performance
@@ -147,31 +152,32 @@ extension UnsafeBufferPointer {
147152
_position: UnsafePointer<Element>?,
148153
_end: UnsafePointer<Element>?
149154
) {
150-
self._position = _position
151-
self._end = _end
155+
unsafe self._position = _position
156+
unsafe self._end = _end
152157
}
153158
}
154159
}
155160

156161
@available(*, unavailable)
157162
extension UnsafeBufferPointer.Iterator: Sendable {}
158163

159-
extension UnsafeBufferPointer.Iterator: IteratorProtocol {
164+
extension UnsafeBufferPointer.Iterator: @unsafe IteratorProtocol {
160165
/// Advances to the next element and returns it, or `nil` if no next element
161166
/// exists.
162167
///
163168
/// Once `nil` has been returned, all subsequent calls return `nil`.
164169
@inlinable // unsafe-performance
170+
@unsafe
165171
public mutating func next() -> Element? {
166-
guard let start = _position else {
172+
guard let start = unsafe _position else {
167173
return nil
168174
}
169-
_internalInvariant(_end != nil, "inconsistent _position, _end pointers")
175+
_internalInvariant(unsafe _end != nil, "inconsistent _position, _end pointers")
170176

171-
if start == _end._unsafelyUnwrappedUnchecked { return nil }
177+
if unsafe start == _end._unsafelyUnwrappedUnchecked { return nil }
172178

173179
let result = unsafe start.pointee
174-
_position = start + 1
180+
unsafe _position = start + 1
175181
return result
176182
}
177183
}
@@ -213,6 +219,7 @@ extension Unsafe${Mutable}BufferPointer: @unsafe Sequence {
213219
}
214220

215221
@inlinable
222+
@safe
216223
public func withContiguousStorageIfAvailable<R>(
217224
_ body: (UnsafeBufferPointer<Element>) throws -> R
218225
) rethrows -> R? {
@@ -232,6 +239,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
232239
/// - Complexity: O(1)
233240
@_alwaysEmitIntoClient
234241
@_preInverseGenerics
242+
@safe
235243
public var isEmpty: Bool { count == 0 }
236244

237245
/// The index of the first element in a nonempty buffer.
@@ -240,6 +248,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
240248
/// is always zero.
241249
@inlinable
242250
@_preInverseGenerics
251+
@safe
243252
public var startIndex: Int { 0 }
244253

245254
/// The "past the end" position---that is, the position one greater than the
@@ -249,10 +258,12 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
249258
/// always identical to `count`.
250259
@inlinable
251260
@_preInverseGenerics
261+
@safe
252262
public var endIndex: Int { count }
253263

254264
@inlinable
255265
@_preInverseGenerics
266+
@unsafe
256267
public func index(after i: Int) -> Int {
257268
// NOTE: this is a manual specialization of index movement for a Strideable
258269
// index that is required for UnsafeBufferPointer performance. The
@@ -271,6 +282,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
271282

272283
@inlinable
273284
@_preInverseGenerics
285+
@unsafe
274286
public func formIndex(after i: inout Int) {
275287
// NOTE: this is a manual specialization of index movement for a Strideable
276288
// index that is required for UnsafeBufferPointer performance. The
@@ -285,6 +297,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
285297

286298
@inlinable
287299
@_preInverseGenerics
300+
@unsafe
288301
public func index(before i: Int) -> Int {
289302
// NOTE: this is a manual specialization of index movement for a Strideable
290303
// index that is required for UnsafeBufferPointer performance. The
@@ -299,6 +312,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
299312

300313
@inlinable
301314
@_preInverseGenerics
315+
@unsafe
302316
public func formIndex(before i: inout Int) {
303317
// NOTE: this is a manual specialization of index movement for a Strideable
304318
// index that is required for UnsafeBufferPointer performance. The
@@ -313,6 +327,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
313327

314328
@inlinable
315329
@_preInverseGenerics
330+
@unsafe
316331
public func index(_ i: Int, offsetBy n: Int) -> Int {
317332
// NOTE: this is a manual specialization of index movement for a Strideable
318333
// index that is required for UnsafeBufferPointer performance. The
@@ -327,6 +342,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
327342

328343
@inlinable
329344
@_preInverseGenerics
345+
@unsafe
330346
public func index(_ i: Int, offsetBy n: Int, limitedBy limit: Int) -> Int? {
331347
// NOTE: this is a manual specialization of index movement for a Strideable
332348
// index that is required for UnsafeBufferPointer performance. The
@@ -349,6 +365,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
349365

350366
@inlinable
351367
@_preInverseGenerics
368+
@safe
352369
public func distance(from start: Int, to end: Int) -> Int {
353370
// NOTE: this is a manual specialization of index movement for a Strideable
354371
// index that is required for UnsafeBufferPointer performance. The
@@ -500,6 +517,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
500517
/// - Parameter bounds: A valid range of indices within this buffer.
501518
/// - Returns: A new buffer pointer over the items at `bounds`.
502519
@_alwaysEmitIntoClient
520+
@safe
503521
public func extracting(_ bounds: Range<Int>) -> Self {
504522
_precondition(bounds.lowerBound >= 0 && bounds.upperBound <= count,
505523
"Index out of range")
@@ -538,6 +556,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
538556
/// - Parameter bounds: A valid range of indices within this buffer.
539557
/// - Returns: A new buffer pointer over the items at `bounds`.
540558
@_alwaysEmitIntoClient
559+
@safe
541560
public func extracting(_ bounds: some RangeExpression<Int>) -> Self {
542561
extracting(bounds.relative(to: unsafe Range(uncheckedBounds: (0, count))))
543562
}
@@ -557,6 +576,7 @@ extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
557576
//
558577
/// - Returns: The same buffer as `self`.
559578
@_alwaysEmitIntoClient
579+
@safe
560580
public func extracting(_ bounds: UnboundedRange) -> Self {
561581
self
562582
}
@@ -627,6 +647,7 @@ extension Unsafe${Mutable}BufferPointer {
627647

628648
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
629649
@usableFromInline
650+
@unsafe
630651
internal subscript(_unchecked i: Int) -> Element {
631652
get {
632653
_internalInvariant(i >= 0)
@@ -655,20 +676,23 @@ extension Unsafe${Mutable}BufferPointer:
655676
public typealias SubSequence = Slice<Unsafe${Mutable}BufferPointer<Element>>
656677

657678
@inlinable // unsafe-performance
679+
@safe
658680
public func _failEarlyRangeCheck(_ index: Int, bounds: Range<Int>) {
659681
// NOTE: In release mode, this method is a no-op for performance reasons.
660682
_debugPrecondition(index >= bounds.lowerBound)
661683
_debugPrecondition(index < bounds.upperBound)
662684
}
663685

664686
@inlinable // unsafe-performance
687+
@safe
665688
public func _failEarlyRangeCheck(_ range: Range<Int>, bounds: Range<Int>) {
666689
// NOTE: In release mode, this method is a no-op for performance reasons.
667690
_debugPrecondition(range.lowerBound >= bounds.lowerBound)
668691
_debugPrecondition(range.upperBound <= bounds.upperBound)
669692
}
670693

671694
@inlinable // unsafe-performance
695+
@safe
672696
public var indices: Indices {
673697
// Not checked because init forbids negative count.
674698
return unsafe Indices(uncheckedBounds: (startIndex, endIndex))
@@ -741,14 +765,15 @@ extension Unsafe${Mutable}BufferPointer:
741765
% if Mutable:
742766
@inlinable
743767
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
768+
@safe
744769
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
745770
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
746771
) rethrows -> R? {
747772
return try body(&self)
748773
}
749774

750775
@inlinable
751-
@unsafe
776+
@safe
752777
public mutating func withContiguousMutableStorageIfAvailable<R>(
753778
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
754779
) rethrows -> R? {
@@ -875,6 +900,7 @@ extension UnsafeMutableBufferPointer where Element: ~Copyable {
875900
/// of `Element`.
876901
@inlinable
877902
@_preInverseGenerics
903+
@safe
878904
public static func allocate(
879905
capacity count: Int
880906
) -> UnsafeMutableBufferPointer<Element> {
@@ -1038,7 +1064,7 @@ extension UnsafeMutableBufferPointer {
10381064
while index < endIndex {
10391065
guard let element = iterator.next() else { break }
10401066
unsafe _position._unsafelyUnwrappedUnchecked[index] = element
1041-
formIndex(after: &index)
1067+
unsafe formIndex(after: &index)
10421068
}
10431069
return (iterator, index)
10441070
}
@@ -1102,7 +1128,7 @@ extension UnsafeMutableBufferPointer {
11021128
break
11031129
}
11041130
unsafe _position._unsafelyUnwrappedUnchecked[index] = value
1105-
formIndex(after: &index)
1131+
unsafe formIndex(after: &index)
11061132
}
11071133
return index
11081134
}
@@ -1453,6 +1479,7 @@ extension Unsafe${Mutable}BufferPointer: CustomDebugStringConvertible
14531479
where Element: ~Copyable {
14541480
/// A textual representation of the buffer, suitable for debugging.
14551481
@_preInverseGenerics
1482+
@safe
14561483
public var debugDescription: String {
14571484
return "Unsafe${Mutable}BufferPointer"
14581485
+ "(start: \(_position.map(String.init(describing:)) ?? "nil"), count: \(count))"

0 commit comments

Comments
 (0)