From bf56b09395202672baec1b598a694c01fc25459d Mon Sep 17 00:00:00 2001 From: Alexander Belonogov Date: Mon, 13 Nov 2017 19:38:43 +0100 Subject: [PATCH] [SR-6361] Fix Data.withUnsafeMutableBytes() for slices with length < range.lowerBound --- stdlib/public/SDK/Foundation/Data.swift | 8 ++-- test/stdlib/TestData.swift | 49 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/stdlib/public/SDK/Foundation/Data.swift b/stdlib/public/SDK/Foundation/Data.swift index a0b6e8857ca26..8083b9e4586c5 100644 --- a/stdlib/public/SDK/Foundation/Data.swift +++ b/stdlib/public/SDK/Foundation/Data.swift @@ -198,20 +198,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/test/stdlib/TestData.swift b/test/stdlib/TestData.swift index 70792c1917471..69101662f6922 100644 --- a/test/stdlib/TestData.swift +++ b/test/stdlib/TestData.swift @@ -3677,6 +3677,50 @@ class TestData : TestDataSuper { let h3 = d3.hashValue expectEqual(h1, h3) } + + 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 + } + expectEqual(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 + } + expectEqual(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 + } + expectEqual(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 + } + expectEqual(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 + } + expectEqual(data[data.startIndex.advanced(by: 1)], 0xFF) + } } #if !FOUNDATION_XCTEST @@ -3988,6 +4032,11 @@ DataTests.test("test_sliceHash") { TestData().test_sliceHash() } DataTests.test("test_slice_resize_growth") { TestData().test_slice_resize_growth() } DataTests.test("test_sliceEnumeration") { TestData().test_sliceEnumeration() } DataTests.test("test_hashEmptyData") { TestData().test_hashEmptyData() } +DataTests.test("test_validateMutation_slice_withUnsafeMutableBytes_lengthLessThanLowerBound") { TestData().test_validateMutation_slice_withUnsafeMutableBytes_lengthLessThanLowerBound() } +DataTests.test("test_validateMutation_slice_immutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound") { TestData().test_validateMutation_slice_immutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() } +DataTests.test("test_validateMutation_slice_mutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound") { TestData().test_validateMutation_slice_mutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() } +DataTests.test("test_validateMutation_slice_customBacking_withUnsafeMutableBytes_lengthLessThanLowerBound") { TestData().test_validateMutation_slice_customBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() } +DataTests.test("test_validateMutation_slice_customMutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound") { TestData().test_validateMutation_slice_customMutableBacking_withUnsafeMutableBytes_lengthLessThanLowerBound() } // XCTest does not have a crash detection, whereas lit does DataTests.test("bounding failure subdata") {