To begin with the conclusion, the following (experimental) code can be executed successfully on macOS whereas a run-time error happens on Linux.
protocol MyProtocol {
var string: String { get set }
}
struct MyStruct: MyProtocol {
var string: String = "Hello, World!"
}
/// An odd type-erasure.
/// This kind of type is sometimes helpful to communicate with C API.
class PointerWrapper {
private class _PointerBox {
func setString(_ string: String) { fatalError() }
}
private final class _SomePointer<T>: _PointerBox where T: MyProtocol {
let base: UnsafeMutablePointer<T>
init(_ base: UnsafeMutablePointer<T>) { self.base = base }
override func setString(_ string: String) {
base.pointee.string = string
}
}
private let pointer: _PointerBox
init<T>(_ pointer: UnsafeMutablePointer<T>) where T: MyProtocol {
self.pointer = _SomePointer<T>(pointer)
}
func setString(_ string: String) {
pointer.setString(string)
}
}
func useEphemeralPointer<T>(_ object: inout T) where T: MyProtocol {
withUnsafeMutablePointer(to: &object) {
var wrapper = PointerWrapper($0)
withUnsafeMutablePointer(to: &wrapper) {
$0.pointee.setString("Ephemeral.")
}
}
}
func useAllocatedPointer<T>(_ object: inout T) where T: MyProtocol {
let objPointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
objPointer.pointee = object
defer {
object = objPointer.pointee
objPointer.deallocate()
}
let wrapper = PointerWrapper(objPointer)
let wrapperPointer = UnsafeMutablePointer<PointerWrapper>.allocate(capacity: 1)
wrapperPointer.pointee = wrapper
defer {
wrapperPointer.deallocate()
}
wrapperPointer.pointee.setString("Allocated.")
}
var something = MyStruct()
print(something.string) // Prints "Hello, World!"
useEphemeralPointer(&something) // β
Successful on both macOS and Linux.
print(something.string) // Prints "Ephemeral."
useAllocatedPointer(&something) // β On Linux: π£ Program crashed: Bad pointer dereference
print(something.string) // Prints "Allocated." (on macOS).
I think that func useEphemeralPointer and func useAllocatedPointer behaves in the same way (at least from the viewpoint of caller).
I mean I guess the run-time error on Linux seems buggy.
However I am probably missing something.
Then, my question is "Which is the expected behavior? Crash or not?"