Recently, got caught by a problem with my code when using tuples with withUnsafePointer(to:
. Want to highlight this and see some feedback from the community.
TD;LR: This is surprising because you either get incorrect pointer AND correct type or you get correct pointer AND incorrect type.
I know we shouldn't assume any pointer stability when using tuples in Swift. However, when interop with C libraries, they often have structs that contain static arrays. These static arrays will be interop'ed to tuples in Swift. Their C functions will accept the pointer form of these static arrays, making it impossible to avoid withUnsafePointer(to:
family of methods.
However, with these methods, you end up in improbable case where if you want to have the correct type, you will have the incorrect pointer. If you get the pointer correctly, the type is incorrect and requires a cast. Here is the example:
var aCStructWithATuple = ...
aCStructWithATuple.tuple.0 = 10
aCStructWithATuple.tuple.1 = 11
aCStructWithATuple.tuple.2 = 12
let incorrectTuple2 = withUnsafePointer(to: &aCStructWithATuple.tuple.0) { $0[2] }
// This will show random number because $0 is not what you think it is.
let correctTuple2 = withUnsafePointer(to: &aCStructWithATuple.tuple) { UnsafeRawPointer($0).assumingMemoryBound(to: Int32.self)[2] }
// This will show 12, but without cast, the type will be UnsafePointer<(Int32, Int32, Int32, Int32)>
I have a unit test case in swift-mujoco/tuple.swift at main · liuliu/swift-mujoco · GitHub It is pretty easy to modify the test case to show the behavior.
Do you have a better way to handle this? Can I get the correct pointer and the correct type somehow in some way?