Skip to content

Commit b711ed9

Browse files
committed
[Foundation] Data: Hash the entire contents, not just an arbitrary subset
1 parent 6f40a4a commit b711ed9

File tree

2 files changed

+64
-17
lines changed

2 files changed

+64
-17
lines changed

stdlib/public/Darwin/Foundation/Data.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,9 +1046,8 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
10461046
func hash(into hasher: inout Hasher) {
10471047
hasher.combine(count)
10481048

1049-
// At most, hash the first 80 bytes of this data.
1050-
let range = startIndex ..< Swift.min(startIndex + 80, endIndex)
1051-
storage.withUnsafeBytes(in: range) {
1049+
// To ensure strong hashing, all bytes must be fed into the hasher.
1050+
withUnsafeBytes {
10521051
hasher.combine(bytes: $0)
10531052
}
10541053
}
@@ -1250,9 +1249,8 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
12501249
func hash(into hasher: inout Hasher) {
12511250
hasher.combine(count)
12521251

1253-
// Hash at most the first 80 bytes of this data.
1254-
let range = startIndex ..< Swift.min(startIndex + 80, endIndex)
1255-
storage.withUnsafeBytes(in: range) {
1252+
// To ensure strong hashing, all bytes must be fed into the hasher.
1253+
withUnsafeBytes {
12561254
hasher.combine(bytes: $0)
12571255
}
12581256
}

test/stdlib/TestData.swift

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,59 @@ class TestData : TestDataSuper {
974974
expectTrue(d.classForKeyedArchiver == expected)
975975
}
976976

977+
func test_Hashing() {
978+
func bridgedData(_ bytes: [UInt8]) -> Data {
979+
return bytes.withUnsafeBytes { buffer in
980+
NSData(bytes: buffer.baseAddress, length: buffer.count) as Data
981+
}
982+
}
983+
984+
let simpleTests: [[Data]] = [
985+
[
986+
Data(),
987+
bridgedData([]),
988+
],
989+
[
990+
Data([1]),
991+
bridgedData([1]),
992+
],
993+
[
994+
Data([1, 2]),
995+
bridgedData([1, 2]),
996+
],
997+
[
998+
Data([1, 2, 3]),
999+
Data([1, 2, 3]),
1000+
bridgedData([1, 2, 3]),
1001+
bridgedData([1, 2, 3]),
1002+
],
1003+
[
1004+
Data([2, 1, 3]),
1005+
bridgedData([2, 1, 3]),
1006+
],
1007+
]
1008+
checkHashableGroups(simpleTests)
1009+
1010+
// To ensure strong hashing, all bytes must be fed into the hasher.
1011+
let longTest: [Data] = [
1012+
Data([1]) + Data(UInt8.min ... UInt8.max),
1013+
Data([2]) + Data(UInt8.min ... UInt8.max),
1014+
Data(UInt8.min ... UInt8.max) + Data([1]),
1015+
Data(UInt8.min ... UInt8.max) + Data([2]),
1016+
Data(UInt8.min ..< 128) + Data([1]) + Data(128 ... UInt8.max),
1017+
Data(UInt8.min ..< 128) + Data([2]) + Data(128 ... UInt8.max),
1018+
]
1019+
checkHashable(longTest, equalityOracle: { $0 == $1 })
1020+
1021+
let concatenationTest: [[Data]] = [
1022+
[Data([1, 2, 3]), Data()],
1023+
[Data([1, 2]), Data([3])],
1024+
[Data([1]), Data([2, 3])],
1025+
[Data(), Data([1, 2, 3])],
1026+
]
1027+
checkHashable(concatenationTest, equalityOracle: { $0 == $1 })
1028+
}
1029+
9771030
func test_AnyHashableContainingData() {
9781031
let values: [Data] = [
9791032
Data(base64Encoded: "AAAA")!,
@@ -3708,13 +3761,14 @@ class TestData : TestDataSuper {
37083761
let base2 = Data(bytes: [0, 0xFF, 0xFF, 0])
37093762
let base3 = Data(bytes: [0xFF, 0xFF, 0xFF, 0])
37103763
let sliceEmulation = Data(bytes: [0xFF, 0xFF])
3711-
expectEqual(base1.hashValue, base2.hashValue)
37123764
let slice1 = base1[base1.startIndex.advanced(by: 1)..<base1.endIndex.advanced(by: -1)]
37133765
let slice2 = base2[base2.startIndex.advanced(by: 1)..<base2.endIndex.advanced(by: -1)]
37143766
let slice3 = base3[base3.startIndex.advanced(by: 1)..<base3.endIndex.advanced(by: -1)]
3715-
expectEqual(slice1.hashValue, sliceEmulation.hashValue)
3716-
expectEqual(slice1.hashValue, slice2.hashValue)
3717-
expectEqual(slice2.hashValue, slice3.hashValue)
3767+
checkHashableGroups([
3768+
[base1, base2],
3769+
[base3],
3770+
[sliceEmulation, slice1, slice2, slice3],
3771+
])
37183772
}
37193773

37203774
func test_slice_resize_growth() {
@@ -3725,16 +3779,10 @@ class TestData : TestDataSuper {
37253779

37263780
func test_hashEmptyData() {
37273781
let d1 = Data()
3728-
let h1 = d1.hashValue
3729-
37303782
let d2 = NSData() as Data
3731-
let h2 = d2.hashValue
3732-
expectEqual(h1, h2)
3733-
37343783
let data = Data(bytes: [0, 1, 2, 3, 4, 5, 6])
37353784
let d3 = data[4..<4]
3736-
let h3 = d3.hashValue
3737-
expectEqual(h1, h3)
3785+
checkHashableGroups([[d1, d2, d3]])
37383786
}
37393787

37403788
func test_validateMutation_slice_withUnsafeMutableBytes_lengthLessThanLowerBound() {
@@ -3847,6 +3895,7 @@ DataTests.test("test_basicMutableDataMutation") { TestData().test_basicMutableDa
38473895
DataTests.test("test_passing") { TestData().test_passing() }
38483896
DataTests.test("test_bufferSizeCalculation") { TestData().test_bufferSizeCalculation() }
38493897
DataTests.test("test_classForCoder") { TestData().test_classForCoder() }
3898+
DataTests.test("test_Hashing") { TestData().test_Hashing() }
38503899
DataTests.test("test_AnyHashableContainingData") { TestData().test_AnyHashableContainingData() }
38513900
DataTests.test("test_AnyHashableCreatedFromNSData") { TestData().test_AnyHashableCreatedFromNSData() }
38523901
DataTests.test("test_noCopyBehavior") { TestData().test_noCopyBehavior() }

0 commit comments

Comments
 (0)