From 771eff45eb4ced39b7a84d101149a29752224591 Mon Sep 17 00:00:00 2001 From: Alexander Belonogov Date: Sat, 11 Nov 2017 01:23:50 +0100 Subject: [PATCH] [SR-6361] Fix Data.withUnsafeMutableBytes() for slices with length < range.lowerBound --- Foundation/Data.swift | 8 +++--- TestFoundation/TestNSData.swift | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Foundation/Data.swift b/Foundation/Data.swift index 0102662c43..41eebb287c 100644 --- a/Foundation/Data.swift +++ b/Foundation/Data.swift @@ -214,20 +214,20 @@ public final class _DataStorage { 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 db88d57305..f07e2505fe 100644 --- a/TestFoundation/TestNSData.swift +++ b/TestFoundation/TestNSData.swift @@ -509,6 +509,12 @@ class TestNSData: XCTestCase { // ("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 @@ extension TestNSData { 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) 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) 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) 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) 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) in + ptr.advanced(by: 1).pointee = 0xFF + } + XCTAssertEqual(data[data.startIndex.advanced(by: 1)], 0xFF) + } }