Skip to content

Commit c0af06a

Browse files
authored
Merge pull request swiftlang#286 from swiftwasm/main
[pull] swiftwasm from main
2 parents 9161fa9 + 1168239 commit c0af06a

File tree

11 files changed

+196
-146
lines changed

11 files changed

+196
-146
lines changed

Sources/Foundation/Data.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
20412041
@inlinable // This is @inlinable as a convenience initializer.
20422042
public init(contentsOf url: __shared URL, options: Data.ReadingOptions = []) throws {
20432043
let d = try NSData(contentsOf: url, options: ReadingOptions(rawValue: options.rawValue))
2044-
self.init(bytes: d.bytes, count: d.length)
2044+
self = withExtendedLifetime(d) {
2045+
return Data(bytes: d.bytes, count: d.length)
2046+
}
20452047
}
20462048
#endif
20472049

@@ -2053,7 +2055,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
20532055
@inlinable // This is @inlinable as a convenience initializer.
20542056
public init?(base64Encoded base64String: __shared String, options: Data.Base64DecodingOptions = []) {
20552057
if let d = NSData(base64Encoded: base64String, options: Base64DecodingOptions(rawValue: options.rawValue)) {
2056-
self.init(bytes: d.bytes, count: d.length)
2058+
self = withExtendedLifetime(d) {
2059+
Data(bytes: d.bytes, count: d.length)
2060+
}
20572061
} else {
20582062
return nil
20592063
}
@@ -2068,7 +2072,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
20682072
@inlinable // This is @inlinable as a convenience initializer.
20692073
public init?(base64Encoded base64Data: __shared Data, options: Data.Base64DecodingOptions = []) {
20702074
if let d = NSData(base64Encoded: base64Data, options: Base64DecodingOptions(rawValue: options.rawValue)) {
2071-
self.init(bytes: d.bytes, count: d.length)
2075+
self = withExtendedLifetime(d) {
2076+
Data(bytes: d.bytes, count: d.length)
2077+
}
20722078
} else {
20732079
return nil
20742080
}

Sources/Foundation/NSAttributedString.swift

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -558,30 +558,31 @@ internal func _NSReadIntFromMutableAttributedStringCoding(_ data: NSData, _ star
558558
let length = data.length
559559

560560
var value = 0
561-
562-
while offset < length {
563-
let i = Int(data.bytes.load(fromByteOffset: offset, as: UInt8.self))
564-
565-
offset += 1
566-
567-
let isLast = i < 128
568-
569-
let intermediateValue = multiplier.multipliedReportingOverflow(by: isLast ? i : (i - 128))
570-
guard !intermediateValue.overflow else { return nil }
571-
572-
let newValue = value.addingReportingOverflow(intermediateValue.partialValue)
573-
guard !newValue.overflow else { return nil }
574-
575-
value = newValue.partialValue
576561

577-
if isLast {
578-
return (value: value, newOffset: offset)
562+
return withExtendedLifetime(data) { _ -> (Int, Int)? in
563+
while offset < length {
564+
let i = Int(data.bytes.load(fromByteOffset: offset, as: UInt8.self))
565+
566+
offset += 1
567+
568+
let isLast = i < 128
569+
570+
let intermediateValue = multiplier.multipliedReportingOverflow(by: isLast ? i : (i - 128))
571+
guard !intermediateValue.overflow else { return nil }
572+
573+
let newValue = value.addingReportingOverflow(intermediateValue.partialValue)
574+
guard !newValue.overflow else { return nil }
575+
576+
value = newValue.partialValue
577+
578+
if isLast {
579+
return (value: value, newOffset: offset)
580+
}
581+
582+
multiplier *= 128
579583
}
580-
581-
multiplier *= 128
584+
return nil // Getting to the end of the stream indicates error, since we were still expecting more bytes
582585
}
583-
584-
return nil // Getting to the end of the stream indicates error, since we were still expecting more bytes
585586
}
586587

587588
internal func _NSWriteIntToMutableAttributedStringCoding(_ i: Int, _ data: NSMutableData) {

Sources/Foundation/NSData.swift

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,20 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
156156
public init(contentsOfFile path: String, options readOptionsMask: ReadingOptions = []) throws {
157157
super.init()
158158
let readResult = try NSData.readBytesFromFileWithExtendedAttributes(path, options: readOptionsMask)
159-
_init(bytes: readResult.bytes, length: readResult.length, copy: false, deallocator: readResult.deallocator)
159+
160+
withExtendedLifetime(readResult) {
161+
_init(bytes: readResult.bytes, length: readResult.length, copy: false, deallocator: readResult.deallocator)
162+
}
160163
}
161164

162165
/// Initializes a data object with the contents of the file at a given path.
163166
public init?(contentsOfFile path: String) {
164167
do {
165168
super.init()
166169
let readResult = try NSData.readBytesFromFileWithExtendedAttributes(path, options: [])
167-
_init(bytes: readResult.bytes, length: readResult.length, copy: false, deallocator: readResult.deallocator)
170+
withExtendedLifetime(readResult) {
171+
_init(bytes: readResult.bytes, length: readResult.length, copy: false, deallocator: readResult.deallocator)
172+
}
168173
} catch {
169174
return nil
170175
}
@@ -184,15 +189,19 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
184189
public init(contentsOf url: URL, options readOptionsMask: ReadingOptions = []) throws {
185190
super.init()
186191
let (data, _) = try NSData.contentsOf(url: url, options: readOptionsMask)
187-
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
192+
withExtendedLifetime(data) {
193+
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
194+
}
188195
}
189196

190197
/// Initializes a data object with the data from the location specified by a given URL.
191198
public init?(contentsOf url: URL) {
192199
super.init()
193200
do {
194201
let (data, _) = try NSData.contentsOf(url: url)
195-
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
202+
withExtendedLifetime(data) {
203+
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
204+
}
196205
} catch {
197206
return nil
198207
}
@@ -384,15 +393,19 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
384393
guard let data = aDecoder._decodePropertyListForKey("NS.data") as? NSData else {
385394
return nil
386395
}
387-
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
396+
withExtendedLifetime(data) {
397+
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
398+
}
388399
} else {
389400
let result : Data? = aDecoder.withDecodedUnsafeBufferPointer(forKey: "NS.bytes") {
390401
guard let buffer = $0 else { return nil }
391402
return Data(buffer: buffer)
392403
}
393404

394-
guard let r = result else { return nil }
395-
_init(bytes: UnsafeMutableRawPointer(mutating: r._nsObject.bytes), length: r.count, copy: true)
405+
guard var r = result else { return nil }
406+
r.withUnsafeMutableBytes {
407+
_init(bytes: $0.baseAddress, length: $0.count, copy: true)
408+
}
396409
}
397410
}
398411

@@ -571,24 +584,27 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
571584
/// Finds and returns the range of the first occurrence of the given data, within the given range, subject to given options.
572585
open func range(of dataToFind: Data, options mask: SearchOptions = [], in searchRange: NSRange) -> NSRange {
573586
let dataToFind = dataToFind._nsObject
574-
guard dataToFind.length > 0 else {return NSRange(location: NSNotFound, length: 0)}
575-
guard let searchRange = Range(searchRange) else {fatalError("invalid range")}
576-
577-
precondition(searchRange.upperBound <= self.length, "range outside the bounds of data")
578587

579-
let basePtr = self.bytes.bindMemory(to: UInt8.self, capacity: self.length)
580-
let baseData = UnsafeBufferPointer<UInt8>(start: basePtr, count: self.length)[searchRange]
581-
let searchPtr = dataToFind.bytes.bindMemory(to: UInt8.self, capacity: dataToFind.length)
582-
let search = UnsafeBufferPointer<UInt8>(start: searchPtr, count: dataToFind.length)
583-
584-
let location : Int?
585-
let anchored = mask.contains(.anchored)
586-
if mask.contains(.backwards) {
587-
location = NSData.searchSubSequence(search.reversed(), inSequence: baseData.reversed(),anchored : anchored).map {$0.base-search.count}
588-
} else {
589-
location = NSData.searchSubSequence(search, inSequence: baseData,anchored : anchored)
588+
return withExtendedLifetime(dataToFind) {
589+
guard dataToFind.length > 0 else {return NSRange(location: NSNotFound, length: 0)}
590+
guard let searchRange = Range(searchRange) else {fatalError("invalid range")}
591+
592+
precondition(searchRange.upperBound <= self.length, "range outside the bounds of data")
593+
594+
let basePtr = self.bytes.bindMemory(to: UInt8.self, capacity: self.length)
595+
let baseData = UnsafeBufferPointer<UInt8>(start: basePtr, count: self.length)[searchRange]
596+
let searchPtr = dataToFind.bytes.bindMemory(to: UInt8.self, capacity: dataToFind.length)
597+
let search = UnsafeBufferPointer<UInt8>(start: searchPtr, count: dataToFind.length)
598+
599+
let location : Int?
600+
let anchored = mask.contains(.anchored)
601+
if mask.contains(.backwards) {
602+
location = NSData.searchSubSequence(search.reversed(), inSequence: baseData.reversed(),anchored : anchored).map {$0.base-search.count}
603+
} else {
604+
location = NSData.searchSubSequence(search, inSequence: baseData,anchored : anchored)
605+
}
606+
return location.map {NSRange(location: $0, length: search.count)} ?? NSRange(location: NSNotFound, length: 0)
590607
}
591-
return location.map {NSRange(location: $0, length: search.count)} ?? NSRange(location: NSNotFound, length: 0)
592608
}
593609

594610
private static func searchSubSequence<T : Collection, T2 : Sequence>(_ subSequence : T2, inSequence seq: T,anchored : Bool) -> T.Index? where T.Iterator.Element : Equatable, T.Iterator.Element == T2.Iterator.Element {

Sources/Foundation/NSString.swift

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,12 +1377,16 @@ extension NSString {
13771377
public convenience init(contentsOf url: URL, encoding enc: UInt) throws {
13781378
let readResult = try NSData(contentsOf: url, options: [])
13791379

1380-
let bytePtr = readResult.bytes.bindMemory(to: UInt8.self, capacity: readResult.length)
1381-
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr, readResult.length, CFStringConvertNSStringEncodingToEncoding(numericCast(enc)), true) else {
1382-
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInapplicableStringEncoding.rawValue, userInfo: [
1383-
NSDebugDescriptionErrorKey : "Unable to create a string using the specified encoding."
1384-
])
1380+
let cf = try withExtendedLifetime(readResult) { _ -> CFString in
1381+
let bytePtr = readResult.bytes.bindMemory(to: UInt8.self, capacity: readResult.length)
1382+
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr, readResult.length, CFStringConvertNSStringEncodingToEncoding(numericCast(enc)), true) else {
1383+
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInapplicableStringEncoding.rawValue, userInfo: [
1384+
NSDebugDescriptionErrorKey : "Unable to create a string using the specified encoding."
1385+
])
1386+
}
1387+
return cf
13851388
}
1389+
13861390
var str: String?
13871391
if String._conditionallyBridgeFromObjectiveC(cf._nsObject, result: &str) {
13881392
self.init(str!)
@@ -1400,44 +1404,49 @@ extension NSString {
14001404
public convenience init(contentsOf url: URL, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws {
14011405
let (readResult, textEncodingNameMaybe) = try NSData.contentsOf(url: url)
14021406

1403-
let encoding: UInt
1404-
let offset: Int
1405-
// Look for a BOM (Byte Order Marker) to try and determine the text Encoding, this also skips
1406-
// over the bytes. This takes precedence over the textEncoding in the http header
1407-
let bytePtr = readResult.bytes.bindMemory(to: UInt8.self, capacity:readResult.length)
1408-
if readResult.length >= 4 && bytePtr[0] == 0xFF && bytePtr[1] == 0xFE && bytePtr[2] == 0x00 && bytePtr[3] == 0x00 {
1409-
encoding = String.Encoding.utf32LittleEndian.rawValue
1410-
offset = 4
1411-
}
1412-
else if readResult.length >= 2 && bytePtr[0] == 0xFE && bytePtr[1] == 0xFF {
1413-
encoding = String.Encoding.utf16BigEndian.rawValue
1414-
offset = 2
1415-
}
1416-
else if readResult.length >= 2 && bytePtr[0] == 0xFF && bytePtr[1] == 0xFE {
1417-
encoding = String.Encoding.utf16LittleEndian.rawValue
1418-
offset = 2
1419-
}
1420-
else if readResult.length >= 4 && bytePtr[0] == 0x00 && bytePtr[1] == 0x00 && bytePtr[2] == 0xFE && bytePtr[3] == 0xFF {
1421-
encoding = String.Encoding.utf32BigEndian.rawValue
1422-
offset = 4
1423-
}
1424-
else if let charSet = textEncodingNameMaybe, let textEncoding = String.Encoding(charSet: charSet) {
1425-
encoding = textEncoding.rawValue
1426-
offset = 0
1427-
} else {
1428-
//Need to work on more conditions. This should be the default
1429-
encoding = String.Encoding.utf8.rawValue
1430-
offset = 0
1431-
}
14321407

1433-
// Since the encoding being passed includes the byte order the BOM wont be checked or skipped, so pass offset to
1434-
// manually skip the BOM header.
1435-
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr + offset, readResult.length - offset,
1436-
CFStringConvertNSStringEncodingToEncoding(numericCast(encoding)), true) else {
1437-
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInapplicableStringEncoding.rawValue, userInfo: [
1438-
NSDebugDescriptionErrorKey : "Unable to create a string using the specified encoding."
1439-
])
1408+
let (cf, encoding) = try withExtendedLifetime(readResult) { _ -> (CFString, UInt) in
1409+
let encoding: UInt
1410+
let offset: Int
1411+
// Look for a BOM (Byte Order Marker) to try and determine the text Encoding, this also skips
1412+
// over the bytes. This takes precedence over the textEncoding in the http header
1413+
let bytePtr = readResult.bytes.bindMemory(to: UInt8.self, capacity:readResult.length)
1414+
if readResult.length >= 4 && bytePtr[0] == 0xFF && bytePtr[1] == 0xFE && bytePtr[2] == 0x00 && bytePtr[3] == 0x00 {
1415+
encoding = String.Encoding.utf32LittleEndian.rawValue
1416+
offset = 4
1417+
}
1418+
else if readResult.length >= 2 && bytePtr[0] == 0xFE && bytePtr[1] == 0xFF {
1419+
encoding = String.Encoding.utf16BigEndian.rawValue
1420+
offset = 2
1421+
}
1422+
else if readResult.length >= 2 && bytePtr[0] == 0xFF && bytePtr[1] == 0xFE {
1423+
encoding = String.Encoding.utf16LittleEndian.rawValue
1424+
offset = 2
1425+
}
1426+
else if readResult.length >= 4 && bytePtr[0] == 0x00 && bytePtr[1] == 0x00 && bytePtr[2] == 0xFE && bytePtr[3] == 0xFF {
1427+
encoding = String.Encoding.utf32BigEndian.rawValue
1428+
offset = 4
1429+
}
1430+
else if let charSet = textEncodingNameMaybe, let textEncoding = String.Encoding(charSet: charSet) {
1431+
encoding = textEncoding.rawValue
1432+
offset = 0
1433+
} else {
1434+
//Need to work on more conditions. This should be the default
1435+
encoding = String.Encoding.utf8.rawValue
1436+
offset = 0
1437+
}
1438+
1439+
// Since the encoding being passed includes the byte order the BOM wont be checked or skipped, so pass offset to
1440+
// manually skip the BOM header.
1441+
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr + offset, readResult.length - offset,
1442+
CFStringConvertNSStringEncodingToEncoding(numericCast(encoding)), true) else {
1443+
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInapplicableStringEncoding.rawValue, userInfo: [
1444+
NSDebugDescriptionErrorKey : "Unable to create a string using the specified encoding."
1445+
])
1446+
}
1447+
return (cf, encoding)
14401448
}
1449+
14411450
var str: String?
14421451
if String._conditionallyBridgeFromObjectiveC(cf._nsObject, result: &str) {
14431452
self.init(str!)

Sources/Foundation/NSTimeZone.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
9797

9898
public convenience init?(abbreviation: String) {
9999
let abbr = abbreviation._cfObject
100-
guard let name = unsafeBitCast(CFDictionaryGetValue(CFTimeZoneCopyAbbreviationDictionary(), unsafeBitCast(abbr, to: UnsafeRawPointer.self)), to: NSString?.self) else {
100+
let possibleName: NSString? = withExtendedLifetime(abbr) {
101+
return unsafeBitCast(CFDictionaryGetValue(CFTimeZoneCopyAbbreviationDictionary(), unsafeBitCast(abbr, to: UnsafeRawPointer.self)), to: NSString?.self)
102+
}
103+
guard let name = possibleName else {
101104
return nil
102105
}
103106
self.init(name: name._swiftObject , data: nil)

Sources/FoundationNetworking/NSURLRequest.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,10 @@ open class NSURLRequest : NSObject, NSSecureCoding, NSCopying, NSMutableCopying
237237
aCoder.encode(self.cachePolicy.rawValue._bridgeToObjectiveC(), forKey: "NS._cachePolicy")
238238
aCoder.encode(self.timeoutInterval._bridgeToObjectiveC(), forKey: "NS._timeoutInterval")
239239
if let httpBody = self.httpBody?._bridgeToObjectiveC() {
240-
let bytePtr = httpBody.bytes.bindMemory(to: UInt8.self, capacity: httpBody.length)
241-
aCoder.encodeBytes(bytePtr, length: httpBody.length, forKey: "NS.httpBody")
240+
withExtendedLifetime(httpBody) {
241+
let bytePtr = httpBody.bytes.bindMemory(to: UInt8.self, capacity: httpBody.length)
242+
aCoder.encodeBytes(bytePtr, length: httpBody.length, forKey: "NS.httpBody")
243+
}
242244
}
243245
//On macOS input stream is not encoded.
244246
aCoder.encode(self.networkServiceType.rawValue._bridgeToObjectiveC(), forKey: "NS._networkServiceType")

Sources/FoundationNetworking/URLSession/NativeProtocol.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
256256
if case .inMemory(let bodyData) = bodyDataDrain {
257257
var data = Data()
258258
if let body = bodyData {
259-
data = Data(bytes: body.bytes, count: body.length)
259+
withExtendedLifetime(body) {
260+
data = Data(bytes: body.bytes, count: body.length)
261+
}
260262
}
261263
self.client?.urlProtocol(self, didLoad: data)
262264
self.internalState = .taskCompleted

Sources/FoundationNetworking/URLSession/NetworkingSpecific.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class _NSNonfileURLContentLoader: _NSNonfileURLContentLoading {
8585
switch statusCode {
8686
// These are the only valid response codes that data will be returned for, all other codes will be treated as error.
8787
case 101, 200...399, 401, 407:
88-
return (NSData(bytes: UnsafeMutableRawPointer(mutating: (data as NSData).bytes), length: data.count), urlResponse?.textEncodingName)
88+
return (data as NSData, urlResponse?.textEncodingName)
8989

9090
default:
9191
break

Tests/Foundation/Tests/TestNSArray.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,9 @@ class TestNSArray : XCTestCase {
833833
func test_arrayUsedAsCFArrayInvokesArrayMethods() {
834834
let number = 789 as NSNumber
835835
let array = NSMutableArray(array: [123, 456])
836-
CFArraySetValueAtIndex(unsafeBitCast(array, to: CFMutableArray.self), 1, UnsafeRawPointer(Unmanaged.passUnretained(number).toOpaque()))
836+
withExtendedLifetime(number) {
837+
CFArraySetValueAtIndex(unsafeBitCast(array, to: CFMutableArray.self), 1, UnsafeRawPointer(Unmanaged.passUnretained(number).toOpaque()))
838+
}
837839
XCTAssertEqual(array[0] as! NSNumber, 123 as NSNumber)
838840
XCTAssertEqual(array[1] as! NSNumber, 789 as NSNumber)
839841
}

0 commit comments

Comments
 (0)