Perhaps. One thing that I've found interesting when reading the documentation is that it says:
When reading from the pointee
property, the instance referenced by this pointer must already be initialized. When pointee
is used as the left side of an assignment, the instance is updated. The instance must be initialized or this pointer’s Pointee
type must be a trivial type.
While the first sentence says the location must be initialised, the final sentence contains an "or" - and makes it sound as though you may read trivial types from uninitialised memory.
As you note, the docs for load
are stricter/clearer:
The memory at this pointer plus offset
must be properly aligned for accessing T
and initialized to T
or another type that is layout compatible with T
.
Whether or not the load itself is UB, there are some particular situations where invalid loads will create values which will cause UB -- and importantly, there is no possible check you could write to validate the value after it has been loaded.
For instance, simple enums are trivial types, but if they have an invalid bitpattern (likely, if the value came from uninitialised memory), switch
statements that the compiler believed to be exhaustive will not be. I don't believe there is any defined behaviour in that circumstance, and there can be lots of secondary UB as a result:
enum SimpleEnum { case a, b }
let simpleEnumPtr = UnsafeMutablePointer<SimpleEnum>.allocate(capacity: 1)
let anotherValue: String
switch simpleEnumPtr.pointee {
case .a: anotherValue = "a"
case .b: anotherValue = "b"
}
print(anotherValue)
// What if the enum was neither .a or .b?
// There is no check you can write to validate it, either.
In the extreme case, this will cause UB basically everywhere:
// Never is a trivial type, right?
let oh_no = UnsafeMutablePointer<Never>.allocate(capacity: 1).pointee
IMO, the documentation for .pointee
should lose the condition about Pointee
being a trivial type.