Skip to content

Commit 1a9f7af

Browse files
committed
[Foundation] Fix Data.count’s setter
Data provides a settable `count` property. Its expected behavior is undocumented, but based on the implementation, it is intended to zero-extend (or truncate) the collection to the specified length. This does not work correctly if we start with an empty Data and we try to increase the count by a small integer: ``` import Foundation var d = Data() d.count = 2 print(d.count) // ⟹ 0 ⁉️ d.count = 100 print(d.count) // ⟹ 100 ✓ ``` It looks like this bug was introduced with the Data overhaul that shipped in Swift 5. (This issue was uncovered by swiftlang#28918.) rdar://58134026
1 parent 2007515 commit 1a9f7af

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

stdlib/public/Darwin/Foundation/Data.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
14021402
if newValue == 0 {
14031403
return nil
14041404
} else if InlineData.canStore(count: newValue) {
1405-
return .inline(InlineData())
1405+
return .inline(InlineData(count: newValue))
14061406
} else if InlineSlice.canStore(count: newValue) {
14071407
return .slice(InlineSlice(count: newValue))
14081408
} else {

test/stdlib/TestData.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3836,6 +3836,53 @@ class TestData : TestDataSuper {
38363836
}
38373837
}
38383838
}
3839+
3840+
func test_increaseCount() {
3841+
guard #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) else { return }
3842+
let initials: [Range<UInt8>] = [
3843+
0..<0,
3844+
0..<2,
3845+
0..<4,
3846+
0..<8,
3847+
0..<16,
3848+
0..<32,
3849+
0..<64
3850+
]
3851+
let diffs = [0, 1, 2, 4, 8, 16, 32]
3852+
for initial in initials {
3853+
for diff in diffs {
3854+
var data = Data(initial)
3855+
data.count += diff
3856+
expectEqualSequence(
3857+
Array(initial) + Array(repeating: 0, count: diff),
3858+
data)
3859+
}
3860+
}
3861+
}
3862+
3863+
func test_decreaseCount() {
3864+
guard #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) else { return }
3865+
let initials: [Range<UInt8>] = [
3866+
0..<0,
3867+
0..<2,
3868+
0..<4,
3869+
0..<8,
3870+
0..<16,
3871+
0..<32,
3872+
0..<64
3873+
]
3874+
let diffs = [0, 1, 2, 4, 8, 16, 32]
3875+
for initial in initials {
3876+
for diff in diffs {
3877+
guard initial.count >= diff else { continue }
3878+
var data = Data(initial)
3879+
data.count -= diff
3880+
expectEqualSequence(
3881+
initial.dropLast(diff),
3882+
data)
3883+
}
3884+
}
3885+
}
38393886
}
38403887

38413888
#if !FOUNDATION_XCTEST
@@ -4159,6 +4206,9 @@ if #available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) {
41594206
DataTests.test("test_nsdataSequence") { TestData().test_nsdataSequence() }
41604207
DataTests.test("test_dispatchSequence") { TestData().test_dispatchSequence() }
41614208
}
4209+
DataTests.test("test_increaseCount") { TestData().test_increaseCount() }
4210+
DataTests.test("test_decreaseCount") { TestData().test_decreaseCount() }
4211+
41624212

41634213
// XCTest does not have a crash detection, whereas lit does
41644214
DataTests.test("bounding failure subdata") {

0 commit comments

Comments
 (0)