Skip to content

Commit 28a529c

Browse files
committed
Fix crashes in Unsafe[Raw]BufferPointer with nil baseAddress.
This fix updates various initializers to handle incoming empty buffers that happen to have a nil base. They should simply create another buffer with nil base rather than crashing! It is valid for an Unsafe[Raw]BufferPointer can have a nil base address. This allows round-tripping with C code that takes a pointer/length pair and uses `0` as the pointer value. The original design wrongly assumed that we would use a sentinel value for empty buffers and was never updated for or tested with the current design. Fixes <rdar://problem/47946984> Regression in Foundation.Data's UnsafeBufferPointer constructor.
1 parent dd52105 commit 28a529c

File tree

4 files changed

+55
-11
lines changed

4 files changed

+55
-11
lines changed

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,8 @@ extension Unsafe${Mutable}BufferPointer {
496496
/// - Parameter slice: The buffer slice to rebase.
497497
@inlinable // unsafe-performance
498498
public init(rebasing slice: Slice<UnsafeBufferPointer<Element>>) {
499-
self.init(start: slice.base.baseAddress! + slice.startIndex,
500-
count: slice.count)
499+
let base = slice.base.baseAddress?.advanced(by: slice.startIndex)
500+
self.init(start: base, count: slice.count)
501501
}
502502

503503
% end
@@ -523,9 +523,8 @@ extension Unsafe${Mutable}BufferPointer {
523523
/// - Parameter slice: The buffer slice to rebase.
524524
@inlinable // unsafe-performance
525525
public init(rebasing slice: Slice<UnsafeMutableBufferPointer<Element>>) {
526-
self.init(
527-
start: slice.base.baseAddress! + slice.startIndex,
528-
count: slice.count)
526+
let base = slice.base.baseAddress?.advanced(by: slice.startIndex)
527+
self.init(start: base, count: slice.count)
529528
}
530529

531530
/// Deallocates the memory block previously allocated at this buffer pointer’s

stdlib/public/core/UnsafeRawBufferPointer.swift.gyb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ extension Unsafe${Mutable}RawBufferPointer {
467467
/// buffer's type `T` must be a trivial type.
468468
@inlinable
469469
public init<T>(_ buffer: UnsafeMutableBufferPointer<T>) {
470-
self.init(start: buffer.baseAddress!,
470+
self.init(start: buffer.baseAddress,
471471
count: buffer.count * MemoryLayout<T>.stride)
472472
}
473473

@@ -478,7 +478,7 @@ extension Unsafe${Mutable}RawBufferPointer {
478478
/// buffer's type `T` must be a trivial type.
479479
@inlinable
480480
public init<T>(_ buffer: UnsafeBufferPointer<T>) {
481-
self.init(start: buffer.baseAddress!,
481+
self.init(start: buffer.baseAddress,
482482
count: buffer.count * MemoryLayout<T>.stride)
483483
}
484484
% end # !mutable
@@ -506,8 +506,8 @@ extension Unsafe${Mutable}RawBufferPointer {
506506
/// - Parameter slice: The raw buffer slice to rebase.
507507
@inlinable
508508
public init(rebasing slice: Slice<UnsafeRawBufferPointer>) {
509-
self.init(start: slice.base.baseAddress! + slice.startIndex,
510-
count: slice.count)
509+
let base = slice.base.baseAddress?.advanced(by: slice.startIndex)
510+
self.init(start: base, count: slice.count)
511511
}
512512
% end # !mutable
513513

@@ -533,8 +533,8 @@ extension Unsafe${Mutable}RawBufferPointer {
533533
/// - Parameter slice: The raw buffer slice to rebase.
534534
@inlinable
535535
public init(rebasing slice: Slice<UnsafeMutableRawBufferPointer>) {
536-
self.init(start: slice.base.baseAddress! + slice.startIndex,
537-
count: slice.count)
536+
let base = slice.base.baseAddress?.advanced(by: slice.startIndex)
537+
self.init(start: base, count: slice.count)
538538
}
539539

540540
/// A pointer to the first byte of the buffer.

test/stdlib/UnsafeRawBufferPointer.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ UnsafeRawBufferPointerTestSuite.test("initFromValue") {
3939
expectEqual(value2, value1)
4040
}
4141

42+
UnsafeRawBufferPointerTestSuite.test("initFromNilBuffer") {
43+
let urbp1 =
44+
UnsafeRawBufferPointer(UnsafeBufferPointer<Int>(start: nil, count: 0))
45+
expectEqual(urbp1.baseAddress, nil)
46+
47+
let urbp2 =
48+
UnsafeRawBufferPointer(UnsafeMutableBufferPointer<Int>(start: nil, count: 0))
49+
expectEqual(urbp2.baseAddress, nil)
50+
51+
let umrbp =
52+
UnsafeMutableRawBufferPointer(
53+
UnsafeMutableBufferPointer<Int>(start: nil, count: 0))
54+
expectEqual(umrbp.baseAddress, nil)
55+
}
56+
57+
UnsafeRawBufferPointerTestSuite.test("initFromNilSlice") {
58+
let urbp1 =
59+
UnsafeRawBufferPointer(
60+
rebasing: UnsafeRawBufferPointer(start: nil, count: 0)[...])
61+
expectEqual(urbp1.baseAddress, nil)
62+
63+
let urbp2 =
64+
UnsafeRawBufferPointer(
65+
rebasing: UnsafeMutableRawBufferPointer(start: nil, count: 0)[...])
66+
expectEqual(urbp2.baseAddress, nil)
67+
68+
let umrbp =
69+
UnsafeMutableRawBufferPointer(
70+
rebasing: UnsafeMutableRawBufferPointer(start: nil, count: 0)[...])
71+
expectEqual(umrbp.baseAddress, nil)
72+
}
73+
4274
// Test mutability and subscript getter/setters.
4375
UnsafeRawBufferPointerTestSuite.test("nonmutating_subscript_setter") {
4476
var value1: Int32 = -1

validation-test/stdlib/UnsafeBufferPointer.swift.gyb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ ${SelfName}TestSuite.test("rebasing") {
104104
expectEqual(rebased2[0], slice[i + 1])
105105
}
106106
}
107+
108+
let rebased3 = ${SelfType}(rebasing: ${SelfType}(start: nil, count: 0)[...])
109+
expectEqual(rebased3.baseAddress, nil)
110+
111+
% if not IsMutable:
112+
% if IsRaw:
113+
let rebased4 = ${SelfType}(rebasing: UnsafeMutableRawBufferPointer(start: nil, count: 0)[...])
114+
expectEqual(rebased4.baseAddress, nil)
115+
% else:
116+
let rebased4 = ${SelfType}(rebasing: UnsafeMutableBufferPointer<Float>(start: nil, count: 0)[...])
117+
expectEqual(rebased4.baseAddress, nil)
118+
% end # !Raw
119+
% end # Mutable
107120
}
108121

109122
// Allocate two buffers. Initialize one and copy it into the other. Pass those

0 commit comments

Comments
 (0)