Skip to content

Commit 7f09bbf

Browse files
authored
Merge pull request #33698 from atrick/fix-smallstring
Fix undefined behavior in SmallString.withUTF8
2 parents bfbeb90 + 42bf92a commit 7f09bbf

File tree

4 files changed

+32
-16
lines changed

4 files changed

+32
-16
lines changed

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
688688
case SILInstructionKind::BaseAddrForOffsetInst:
689689
case SILInstructionKind::EndLifetimeInst:
690690
case SILInstructionKind::UncheckedOwnershipConversionInst:
691+
case SILInstructionKind::BindMemoryInst:
691692
return InlineCost::Free;
692693

693694
// Typed GEPs are free.
@@ -798,7 +799,6 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
798799
case SILInstructionKind::AllocRefDynamicInst:
799800
case SILInstructionKind::AllocStackInst:
800801
case SILInstructionKind::AllocValueBufferInst:
801-
case SILInstructionKind::BindMemoryInst:
802802
case SILInstructionKind::BeginApplyInst:
803803
case SILInstructionKind::ValueMetatypeInst:
804804
case SILInstructionKind::WitnessMethodInst:

stdlib/public/core/SmallString.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,26 +197,30 @@ extension _SmallString {
197197
internal func withUTF8<Result>(
198198
_ f: (UnsafeBufferPointer<UInt8>) throws -> Result
199199
) rethrows -> Result {
200+
let count = self.count
200201
var raw = self.zeroTerminatedRawCodeUnits
201-
return try Swift.withUnsafeBytes(of: &raw) { rawBufPtr in
202-
let ptr = rawBufPtr.baseAddress._unsafelyUnwrappedUnchecked
203-
.assumingMemoryBound(to: UInt8.self)
204-
return try f(UnsafeBufferPointer(start: ptr, count: self.count))
202+
return try Swift.withUnsafeBytes(of: &raw) {
203+
let rawPtr = $0.baseAddress._unsafelyUnwrappedUnchecked
204+
// Rebind the underlying (UInt64, UInt64) tuple to UInt8 for the
205+
// duration of the closure. Accessing self after this rebind is undefined.
206+
let ptr = rawPtr.bindMemory(to: UInt8.self, capacity: count)
207+
defer {
208+
// Restore the memory type of self._storage
209+
_ = rawPtr.bindMemory(to: RawBitPattern.self, capacity: 1)
210+
}
211+
return try f(UnsafeBufferPointer(start: ptr, count: count))
205212
}
206213
}
207214

208215
// Overwrite stored code units, including uninitialized. `f` should return the
209216
// new count.
210217
@inline(__always)
211218
internal mutating func withMutableCapacity(
212-
_ f: (UnsafeMutableBufferPointer<UInt8>) throws -> Int
219+
_ f: (UnsafeMutableRawBufferPointer) throws -> Int
213220
) rethrows {
214221
let len = try withUnsafeMutableBytes(of: &self._storage) {
215222
(rawBufPtr: UnsafeMutableRawBufferPointer) -> Int in
216-
let ptr = rawBufPtr.baseAddress._unsafelyUnwrappedUnchecked
217-
.assumingMemoryBound(to: UInt8.self)
218-
return try f(UnsafeMutableBufferPointer(
219-
start: ptr, count: _SmallString.capacity))
223+
return try f(rawBufPtr)
220224
}
221225
if len == 0 {
222226
self = _SmallString()
@@ -273,7 +277,17 @@ extension _SmallString {
273277
) rethrows {
274278
self.init()
275279
try self.withMutableCapacity {
276-
return try initializer($0)
280+
let capacity = $0.count
281+
let rawPtr = $0.baseAddress._unsafelyUnwrappedUnchecked
282+
// Rebind the underlying (UInt64, UInt64) tuple to UInt8 for the
283+
// duration of the closure. Accessing self after this rebind is undefined.
284+
let ptr = rawPtr.bindMemory(to: UInt8.self, capacity: capacity)
285+
defer {
286+
// Restore the memory type of self._storage
287+
_ = rawPtr.bindMemory(to: RawBitPattern.self, capacity: 1)
288+
}
289+
return try initializer(
290+
UnsafeMutableBufferPointer<UInt8>(start: ptr, count: capacity))
277291
}
278292
self._invariantCheck()
279293
}

stdlib/public/core/StringBridge.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ internal func _cocoaStringSubscript(
169169
@_effects(releasenone)
170170
private func _NSStringCopyUTF8(
171171
_ o: _StringSelectorHolder,
172-
into bufPtr: UnsafeMutableBufferPointer<UInt8>
172+
into bufPtr: UnsafeMutableRawBufferPointer
173173
) -> Int? {
174174
let ptr = bufPtr.baseAddress._unsafelyUnwrappedUnchecked
175175
let len = o.length
@@ -193,7 +193,7 @@ private func _NSStringCopyUTF8(
193193
@_effects(releasenone)
194194
internal func _cocoaStringCopyUTF8(
195195
_ target: _CocoaString,
196-
into bufPtr: UnsafeMutableBufferPointer<UInt8>
196+
into bufPtr: UnsafeMutableRawBufferPointer
197197
) -> Int? {
198198
return _NSStringCopyUTF8(_objc(target), into: bufPtr)
199199
}
@@ -206,7 +206,7 @@ private func _NSStringUTF8Count(
206206
var remainingRange = _SwiftNSRange(location: 0, length: 0)
207207
var usedLen = 0
208208
let success = 0 != o.getBytes(
209-
UnsafeMutablePointer<UInt8>(Builtin.inttoptr_Word(0._builtinWordValue)),
209+
UnsafeMutableRawPointer(Builtin.inttoptr_Word(0._builtinWordValue)),
210210
maxLength: 0,
211211
usedLength: &usedLen,
212212
encoding: _cocoaUTF8Encoding,
@@ -340,7 +340,7 @@ internal enum _KnownCocoaString {
340340
@_effects(releasenone) // @opaque
341341
internal func _bridgeTagged(
342342
_ cocoa: _CocoaString,
343-
intoUTF8 bufPtr: UnsafeMutableBufferPointer<UInt8>
343+
intoUTF8 bufPtr: UnsafeMutableRawBufferPointer
344344
) -> Int? {
345345
_internalInvariant(_isObjCTaggedPointer(cocoa))
346346
return _cocoaStringCopyUTF8(cocoa, into: bufPtr)

stdlib/public/core/StringGuts.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ extension _StringGuts {
250250
) -> Int? {
251251
#if _runtime(_ObjC)
252252
// Currently, foreign means NSString
253-
if let res = _cocoaStringCopyUTF8(_object.cocoaObject, into: mbp) {
253+
if let res = _cocoaStringCopyUTF8(_object.cocoaObject,
254+
into: UnsafeMutableRawBufferPointer(start: mbp.baseAddress,
255+
count: mbp.count)) {
254256
return res
255257
}
256258

0 commit comments

Comments
 (0)