[swift-users] UnsafeMutableRawPointer to UnsafeMutablePointer<T>: EXC_BAD_ACCESS on pointee

nyg nyg nygmlist at gmail.com
Tue Sep 26 03:29:21 CDT 2017


Thanks Braden for pointing out that toOpaque() was just a cast of c to
UnsafeMutableRawPointer. And thanks Guillaume too, I now understand why
my code doesn't and can't work.

All this messing around has confused me greatly and I lost track of
what I originally wanted to do :).

At first, I wanted to find where an instance was located in memory. For
structures, it's trivial: UnsafeMutablePointer<T>(&myStruct).

I now understand why it can't work in the same way for reference types.
When doing UnsafeMutablePointer<T>(&myClass) it creates a pointer on
the reference. The pointer does not point to where the class instance
is stored but to where the reference is stored.

By pointing to the reference and not to the class instance data is the
reason we can do pointer.pointee (assuming I read the source code
correctly, pointee just returns self). If the pointer pointed to the
class instance data (as is the case with my rawPointer), doing
pointer.pointee means telling the runtime that the class instance data
is its reference. Which is of course not correct.

Thanks Guillaume for your explanations ;).

Braden you write:

withUnsafeMutablePointer(to: &c) { unsafeMutablePointer in
    print(unsafeMutablePointer)
    print(rawPointer)
}

They shouldn't be the same: unsafeMutablePointer is a pointer on the c
reference while rawPointer is a pointer on the instance data.

But if one wants a pointer on the reference one can simply do:

let referencePointer = UnsafeMutablePointer<C>(&c)

As the c variable contains the memory address of the instance data,
casting it to an Int will give us the instance data location:

String(format: "%p", unsafeBitCast(c, Int.self))

Ok, I won't make this any longer. The doc for the toOpaque() makes more
sense now: "Unsafely converts an unmanaged class reference to a
pointer."

Sorry if this is trivial to some of you, I just needed to write it out
to understand it :).


Thanks again for the help!


On 24 September 2017 at 13:28, Guillaume Lessard via swift-users
<swift-users at swift.org> wrote:
> [re-sending to the list, and elaborating]
>
> You are making the runtime use the first word of the referent as if it were the reference.
>
> The lowercase-c variable is a reference. rawPointer contains the same value, and points to the beginning of the object data. Your typecasting is telling the runtime that pointer.pointee is a *reference*, but ‘pointer’ points to object data. The print statement attempts to dereference data that is not a pointer at all.
>
> Consider this:
>
> let badThingToDo = rawPointer.assumingMemoryBound(to: Int.self)[2] // contains 42
>
> The first word at rawPointer is type data, the second has reference counts (or the side table pointer), the third has the first word of instance data.
>
> Note that c is alive, and Unmanaged’s implementation is fine (we wouldn’t have made it this far if it weren’t).
>
> Guillaume Lessard
>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users


More information about the swift-users mailing list