[SR-6361] Fix Data.withUnsafeMutableBytes() for slices with length < range.lowerBound (#1314)
diff --git a/Foundation/Data.swift b/Foundation/Data.swift
index 0102662..41eebb2 100644
--- a/Foundation/Data.swift
+++ b/Foundation/Data.swift
@@ -214,20 +214,20 @@
switch _backing {
case .swift: fallthrough
case .mutable:
- return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, _length - range.lowerBound)))
+ return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, _length)))
case .customMutableReference(let d):
let len = d.length
- return try apply(UnsafeMutableRawBufferPointer(start: d.mutableBytes.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, len - range.lowerBound)))
+ return try apply(UnsafeMutableRawBufferPointer(start: d.mutableBytes.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, len)))
case .immutable(let d):
let data = d.mutableCopy() as! NSMutableData
_backing = .mutable(data)
_bytes = data.mutableBytes
- return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, _length - range.lowerBound)))
+ return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, _length)))
case .customReference(let d):
let data = d.mutableCopy() as! NSMutableData
_backing = .customMutableReference(data)
let len = data.length
- return try apply(UnsafeMutableRawBufferPointer(start: data.mutableBytes.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, len - range.lowerBound)))
+ return try apply(UnsafeMutableRawBufferPointer(start: data.mutableBytes.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, len)))
}
}
diff --git a/TestFoundation/TestNSData.swift b/TestFoundation/TestNSData.swift
index db88d57..f07e250 100644
--- a/TestFoundation/TestNSData.swift
+++ b/TestFoundation/TestNSData.swift
@@ -509,6 +509,12 @@
// ("test_sliceEnumeration", test_sliceEnumeration),
("test_sliceInsertion", test_sliceInsertion),
("test_sliceDeletion", test_sliceDeletion),
+ ("test_validateMutation_slice_withUnsafeMutableBytes_lengthLessThanLowerBound", test_validateMutation_slice_withUnsafeMutableBytes_lengthLessThanLowerBound),
+ ("test_validateMutation_slice_immutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound", test_validateMutation_slice_immutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound),
+ ("test_validateMutation_slice_mutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound", test_validateMutation_slice_mutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound),
+ ("test_validateMutation_slice_customBacking_withUnsafeMutableBytes_lengthLessThanLowerBound", test_validateMutation_slice_customBacking_withUnsafeMutableBytes_lengthLessThanLowerBound),
+ ("test_validateMutation_slice_customMutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound",
+ test_validateMutation_slice_customMutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound),
]
}
@@ -3979,5 +3985,49 @@
XCTAssertEqual(mutableSliceData.startIndex, 2)
XCTAssertEqual(mutableSliceData.endIndex, sliceData.endIndex - numberOfElementsToDelete)
}
+
+ func test_validateMutation_slice_withUnsafeMutableBytes_lengthLessThanLowerBound() {
+ var data = Data(bytes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])[4..<6]
+ data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
+ ptr.advanced(by: 1).pointee = 0xFF
+ }
+ XCTAssertEqual(data, Data(bytes: [4, 0xFF]))
+ }
+
+ func test_validateMutation_slice_immutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() {
+ var data = Data(referencing: NSData(bytes: "hello world", length: 11))[4..<6]
+ data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
+ ptr.advanced(by: 1).pointee = 0xFF
+ }
+ XCTAssertEqual(data[data.startIndex.advanced(by: 1)], 0xFF)
+ }
+
+ func test_validateMutation_slice_mutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() {
+ var base = Data(referencing: NSData(bytes: "hello world", length: 11))
+ base.append(contentsOf: [1, 2, 3, 4, 5, 6])
+ var data = base[4..<6]
+ data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
+ ptr.advanced(by: 1).pointee = 0xFF
+ }
+ XCTAssertEqual(data[data.startIndex.advanced(by: 1)], 0xFF)
+ }
+
+ func test_validateMutation_slice_customBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() {
+ var data = Data(referencing: AllOnesImmutableData(length: 10))[4..<6]
+ data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
+ ptr.advanced(by: 1).pointee = 0xFF
+ }
+ XCTAssertEqual(data[data.startIndex.advanced(by: 1)], 0xFF)
+ }
+
+ func test_validateMutation_slice_customMutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() {
+ var base = Data(referencing: AllOnesData(length: 1))
+ base.count = 10
+ var data = base[4..<6]
+ data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
+ ptr.advanced(by: 1).pointee = 0xFF
+ }
+ XCTAssertEqual(data[data.startIndex.advanced(by: 1)], 0xFF)
+ }
}