Skip to content

[stdlib] convert withUnsafeBytes() to typed throws #72074

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 75 additions & 18 deletions stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1207,17 +1207,47 @@ extension ${Self} {
/// of the closure's execution.
/// - Returns: The return value, if any, of the `body` closure.
@inlinable
public func withUnsafeMutableBytes<T, Result>(
@_alwaysEmitIntoClient
public func withUnsafeMutableBytes<T, E: Error, Result>(
of value: inout T,
_ body: (UnsafeMutableRawBufferPointer) throws(E) -> Result
) throws(E) -> Result {
let pointer = UnsafeMutableRawPointer(Builtin.addressof(&value))
return try body(.init(start: pointer, count: MemoryLayout<T>.size))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason for writing this way instead of how the old thing was doing it? Not opposed, just curious 🙂

Copy link
Contributor Author

@glessard glessard Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old way crashed the compiler; going straight to the builtin is a workaround. (Not entirely successful, it seems.)

}

/// ABI: Historical withUnsafeMutableBytes(of:_:) rethrows,
/// expressed as "throws", which is ABI-compatible with "rethrows".
@_silgen_name("$ss22withUnsafeMutableBytes2of_q_xz_q_SwKXEtKr0_lF")
@usableFromInline
func __abi_se0413_withUnsafeMutableBytes<T, Result>(
of value: inout T,
_ body: (UnsafeMutableRawBufferPointer) throws -> Result
) rethrows -> Result
{
) throws -> Result {
return try withUnsafeMutablePointer(to: &value) {
return try body(UnsafeMutableRawBufferPointer(
start: $0, count: MemoryLayout<T>.size))
}
}

/// Invokes the given closure with a buffer pointer covering the raw bytes of
/// the given argument.
///
/// This function is similar to `withUnsafeMutableBytes`, except that it
/// doesn't trigger stack protection for the pointer.
@_alwaysEmitIntoClient
public func _withUnprotectedUnsafeMutableBytes<T, E: Error, Result>(
of value: inout T,
_ body: (UnsafeMutableRawBufferPointer) throws(E) -> Result
) throws(E) -> Result {
#if $BuiltinUnprotectedAddressOf
let pointer = UnsafeMutableRawPointer(Builtin.unprotectedAddressOf(&value))
#else
let pointer = UnsafeMutableRawPointer(Builtin.addressof(&value))
#endif
return try body(.init(start: pointer, count: MemoryLayout<T>.size))
}

/// Invokes the given closure with a buffer pointer covering the raw bytes of
/// the given argument.
///
Expand All @@ -1242,11 +1272,23 @@ public func withUnsafeMutableBytes<T, Result>(
/// `withUnsafeMutableBytes(of:_:)` instead.
/// - Returns: The return value, if any, of the `body` closure.
@inlinable
public func withUnsafeBytes<T, Result>(
@_alwaysEmitIntoClient
public func withUnsafeBytes<T, E: Error, Result>(
of value: inout T,
_ body: (UnsafeRawBufferPointer) throws(E) -> Result
) throws(E) -> Result {
let address = UnsafeRawPointer(Builtin.addressof(&value))
return try body(.init(start: address, count: MemoryLayout<T>.size))
}

/// ABI: Historical withUnsafeBytes(of:_:) rethrows,
/// expressed as "throws", which is ABI-compatible with "rethrows".
@_silgen_name("$ss15withUnsafeBytes2of_q_xz_q_SWKXEtKr0_lF")
@usableFromInline
func __abi_se0413_withUnsafeBytes<T, Result>(
of value: inout T,
_ body: (UnsafeRawBufferPointer) throws -> Result
) rethrows -> Result
{
) throws -> Result {
return try withUnsafePointer(to: &value) {
try body(UnsafeRawBufferPointer(start: $0, count: MemoryLayout<T>.size))
}
Expand All @@ -1258,14 +1300,16 @@ public func withUnsafeBytes<T, Result>(
/// This function is similar to `withUnsafeBytes`, except that it
/// doesn't trigger stack protection for the pointer.
@_alwaysEmitIntoClient
public func _withUnprotectedUnsafeBytes<T, Result>(
public func _withUnprotectedUnsafeBytes<T, E: Error, Result>(
of value: inout T,
_ body: (UnsafeRawBufferPointer) throws -> Result
) rethrows -> Result
{
return try _withUnprotectedUnsafePointer(to: &value) {
try body(UnsafeRawBufferPointer(start: $0, count: MemoryLayout<T>.size))
}
_ body: (UnsafeRawBufferPointer) throws(E) -> Result
) throws(E) -> Result {
#if $BuiltinUnprotectedAddressOf
let p = UnsafeRawPointer(Builtin.unprotectedAddressOf(&value))
#else
let p = UnsafeRawPointer(Builtin.addressof(&value))
#endif
return try body(.init(start: p, count: MemoryLayout<T>.size))
}

/// Invokes the given closure with a buffer pointer covering the raw bytes of
Expand All @@ -1288,10 +1332,23 @@ public func _withUnprotectedUnsafeBytes<T, Result>(
/// `withUnsafeMutableBytes(of:_:)` instead.
/// - Returns: The return value, if any, of the `body` closure.
@inlinable
public func withUnsafeBytes<T, Result>(
@_alwaysEmitIntoClient
public func withUnsafeBytes<T, E: Error, Result>(
of value: T,
_ body: (UnsafeRawBufferPointer) throws(E) -> Result
) throws(E) -> Result {
let addr = UnsafeRawPointer(Builtin.addressOfBorrow(value))
return try body(.init(start: addr, count: MemoryLayout<T>.size))
}

/// ABI: Historical withUnsafeBytes(of:_:) rethrows,
/// expressed as "throws", which is ABI-compatible with "rethrows".
@_silgen_name("$ss15withUnsafeBytes2of_q_x_q_SWKXEtKr0_lF")
@usableFromInline
func __abi_se0413_withUnsafeBytes<T, Result>(
of value: T,
_ body: (UnsafeRawBufferPointer) throws -> Result
) rethrows -> Result {
) throws -> Result {
let addr = UnsafeRawPointer(Builtin.addressOfBorrow(value))
let buffer = UnsafeRawBufferPointer(start: addr, count: MemoryLayout<T>.size)
return try body(buffer)
Expand All @@ -1303,10 +1360,10 @@ public func withUnsafeBytes<T, Result>(
/// This function is similar to `withUnsafeBytes`, except that it
/// doesn't trigger stack protection for the pointer.
@_alwaysEmitIntoClient
public func _withUnprotectedUnsafeBytes<T, Result>(
public func _withUnprotectedUnsafeBytes<T, E: Error, Result>(
of value: T,
_ body: (UnsafeRawBufferPointer) throws -> Result
) rethrows -> Result {
_ body: (UnsafeRawBufferPointer) throws(E) -> Result
) throws(E) -> Result {
#if $BuiltinUnprotectedAddressOf
let addr = UnsafeRawPointer(Builtin.unprotectedAddressOfBorrow(value))
#else
Expand Down
10 changes: 10 additions & 0 deletions test/SILOptimizer/stack_protection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ public func unprotectedUnsafeBytes() {
}
}

// CHECK-LABEL: sil @$s4test29unprotectedUnsafeMutableBytesyyF
// CHECK-NOT: copy_addr
// CHECK: } // end sil function '$s4test29unprotectedUnsafeMutableBytesyyF'
public func unprotectedUnsafeMutableBytes() {
var x = 0
_withUnprotectedUnsafeMutableBytes(of: &x) {
potentiallyBadCFunction($0.bindMemory(to: Int.self).baseAddress!)
}
}

// CHECK-LABEL: sil [stack_protection] @$s4test20overflowInCFunction2yyF
// CHECK-NOT: copy_addr
// CHECK: } // end sil function '$s4test20overflowInCFunction2yyF'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Func Sequence.map(_:) is now without @rethrows
Constructor Result.init(catching:) has generic signature change from <Success, Failure where Failure == any Swift.Error> to <Success, Failure where Failure : Swift.Error>
Func withUnsafePointer(to:_:) has generic signature change from <T, Result> to <T, E, Result where E : Swift.Error>
Func withUnsafePointer(to:_:) is now without @rethrows
Func withUnsafeBytes(of:_:) has generic signature change from <T, Result> to <T, E, Result where E : Swift.Error>
Func withUnsafeBytes(of:_:) is now without @rethrows
Func withUnsafeMutableBytes(of:_:) has generic signature change from <T, Result> to <T, E, Result where E : Swift.Error>
Func withUnsafeMutableBytes(of:_:) is now without @rethrows
Func withoutActuallyEscaping(_:do:) has generic signature change from <ClosureType, ResultType> to <ClosureType, ResultType, Failure where Failure : Swift.Error>
Func withoutActuallyEscaping(_:do:) is now without @rethrows

Expand Down
7 changes: 7 additions & 0 deletions test/api-digester/stability-stdlib-abi-without-asserts.test
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ Func Result.get() has mangled name changing from 'Swift.Result.get() throws -> A
Func withUnsafePointer(to:_:) has been renamed to Func __abi_withUnsafePointer(to:_:)
Func withUnsafePointer(to:_:) has mangled name changing from 'Swift.withUnsafePointer<A, B>(to: A, _: (Swift.UnsafePointer<A>) throws -> B) throws -> B' to 'Swift.__abi_withUnsafePointer<A, B>(to: A, _: (Swift.UnsafePointer<A>) throws -> B) throws -> B'
Func withUnsafePointer(to:_:) is now without @rethrows
Func withUnsafeBytes(of:_:) has been renamed to Func __abi_se0413_withUnsafeBytes(of:_:)
Func withUnsafeBytes(of:_:) has mangled name changing from 'Swift.withUnsafeBytes<A, B>(of: A, _: (Swift.UnsafeRawBufferPointer) throws -> B) throws -> B' to 'Swift.__abi_se0413_withUnsafeBytes<A, B>(of: A, _: (Swift.UnsafeRawBufferPointer) throws -> B) throws -> B'
Func withUnsafeBytes(of:_:) has mangled name changing from 'Swift.withUnsafeBytes<A, B>(of: inout A, _: (Swift.UnsafeRawBufferPointer) throws -> B) throws -> B' to 'Swift.__abi_se0413_withUnsafeBytes<A, B>(of: inout A, _: (Swift.UnsafeRawBufferPointer) throws -> B) throws -> B'
Func withUnsafeBytes(of:_:) is now without @rethrows
Func withUnsafeMutableBytes(of:_:) has been renamed to Func __abi_se0413_withUnsafeMutableBytes(of:_:)
Func withUnsafeMutableBytes(of:_:) has mangled name changing from 'Swift.withUnsafeMutableBytes<A, B>(of: inout A, _: (Swift.UnsafeMutableRawBufferPointer) throws -> B) throws -> B' to 'Swift.__abi_se0413_withUnsafeMutableBytes<A, B>(of: inout A, _: (Swift.UnsafeMutableRawBufferPointer) throws -> B) throws -> B'
Func withUnsafeMutableBytes(of:_:) is now without @rethrows
Func withoutActuallyEscaping(_:do:) has been renamed to Func __abi_withoutActuallyEscaping(_:do:)
Func withoutActuallyEscaping(_:do:) has mangled name changing from 'Swift.withoutActuallyEscaping<A, B>(_: A, do: (A) throws -> B) throws -> B' to 'Swift.__abi_withoutActuallyEscaping<A, B>(_: A, do: (A) throws -> B) throws -> B'
Func withoutActuallyEscaping(_:do:) is now without @rethrows
Expand Down