UnsafeMutableRawPointer to UnsafeMutablePointer<T>: EXC_BAD_ACCESS on pointee

Hello all,

I'm trying to get an UnsafeMutablePointer from an
UnsafeMutableRawPointer obtained using the Unmanaged structure:

class C { var foo = 42, bar = "bar" }
let c = C()

let rawPointer = Unmanaged.passUnretained(c).toOpaque()

let pointer = rawPointer.bindMemory(to: C.self, capacity: 1)
let pointee = pointer.pointee
print(pointee.foo) // EXC_BAD_ACCESS

Here's some LLDB output, which looks strange to me as everything seems
alright in pointer until I ask for its pointee:

(lldb) frame variable -L c
scalar: (memtest2.C) c = 0x0000000101d00030 {
0x0000000101d00040: foo = 42
0x0000000101d00048: bar = "bar"
}
(lldb) frame variable -L rawPointer
0x00000001005e2e08: (UnsafeMutableRawPointer) rawPointer = {
scalar: _rawValue = 0x0000000101d00030 {
0x0000000101d00040: foo = 42
0x0000000101d00048: bar = "bar"
}
}
(lldb) frame variable -L pointer
0x00000001005e2e10: (UnsafeMutablePointer<memtest2.C>)
                                            pointer = 0x0000000101d00030
(lldb) frame variable -L pointer._rawValue
scalar: (memtest2.C) pointer._rawValue = 0x0000000101d00030 {
0x0000000101d00040: foo = 42
0x0000000101d00048: bar = "bar"
}
(lldb) frame variable -L pointee
0x00000001005e2e18: (memtest2.C) pointee = 0x00000001005b65d8 {
0x00000001005b65e8: foo = 140736790071664
0x00000001005b65f0: bar = ""
}

I've also tried assumingMemoryBound(to:) or simply doing:

let pointer = UnsafePointer<C>(bitPattern: Int(bitPattern: rawPointer))!
print(pointer.pointee.foo) // EXC_BAD_ACCESS

But I always get this EXC_BAD_ACCESS error. What is going on here?

Thanks for your help,
Nick

Hello all,

I'm trying to get an UnsafeMutablePointer from an
UnsafeMutableRawPointer obtained using the Unmanaged structure:

class C { var foo = 42, bar = "bar" }
let c = C()

let rawPointer = Unmanaged.passUnretained(c).toOpaque()

I believe that the object “c” is effectively dead from this point onwards. Did you try putting a use of c later on to guarantee its lifetime? E.g. add a `dump(c)` at the bottom of your script?

···

On Sep 23, 2017, at 3:44 AM, nyg nyg via swift-users <swift-users@swift.org> wrote:

let pointer = rawPointer.bindMemory(to: C.self, capacity: 1)
let pointee = pointer.pointee
print(pointee.foo) // EXC_BAD_ACCESS

Here's some LLDB output, which looks strange to me as everything seems
alright in pointer until I ask for its pointee:

(lldb) frame variable -L c
scalar: (memtest2.C) c = 0x0000000101d00030 {
0x0000000101d00040: foo = 42
0x0000000101d00048: bar = "bar"
}
(lldb) frame variable -L rawPointer
0x00000001005e2e08: (UnsafeMutableRawPointer) rawPointer = {
scalar: _rawValue = 0x0000000101d00030 {
0x0000000101d00040: foo = 42
0x0000000101d00048: bar = "bar"
}
}
(lldb) frame variable -L pointer
0x00000001005e2e10: (UnsafeMutablePointer<memtest2.C>)
                                           pointer = 0x0000000101d00030
(lldb) frame variable -L pointer._rawValue
scalar: (memtest2.C) pointer._rawValue = 0x0000000101d00030 {
0x0000000101d00040: foo = 42
0x0000000101d00048: bar = "bar"
}
(lldb) frame variable -L pointee
0x00000001005e2e18: (memtest2.C) pointee = 0x00000001005b65d8 {
0x00000001005b65e8: foo = 140736790071664
0x00000001005b65f0: bar = ""
}

I've also tried assumingMemoryBound(to:) or simply doing:

let pointer = UnsafePointer<C>(bitPattern: Int(bitPattern: rawPointer))!
print(pointer.pointee.foo) // EXC_BAD_ACCESS

But I always get this EXC_BAD_ACCESS error. What is going on here?

Thanks for your help,
Nick
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

After doing some testing I looked up the implementation and Unmanaged it is
very misleading in how it is behaves and is implemented.

When you call toOpaque() it returns the result of unsafeBitCast(_value, to:
UnsafeRawPointer.self). _value is an internal field we can't directly
access, in your case it is the c object passed in.

So it seems like it isn't returning a proper UnsafeRawPointer struct.

If you change your let c = C() into var c = C() you can call

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

It will print out different values for the 2 pointers even though they
should be the same. If you test with withUnsafePointer(to:_:) it will give
the closure pointer same address as the unsafeMutablePointer here.

If you need an UnsafeMutablePointer<C> you will need to do something like
this (the pointer passed in is only considered valid for the lifetime of
the closure):

let pointer = withUnsafeMutablePointer(to: &c) {
    return UnsafeMutablePointer<C>($0)
}

If you are fine to use the UnsafeRawPointer from toOpaque(), you can
convert it back into c with:

Unmanaged<C>.fromOpaque(rawPointer).takeUnretainedValue()

Hopefully this helped a bit.

···

On Sat, Sep 23, 2017 at 4:44 PM, Michael Ilseman via swift-users < swift-users@swift.org> wrote:

> On Sep 23, 2017, at 3:44 AM, nyg nyg via swift-users < > swift-users@swift.org> wrote:
>
> Hello all,
>
> I'm trying to get an UnsafeMutablePointer from an
> UnsafeMutableRawPointer obtained using the Unmanaged structure:
>
> class C { var foo = 42, bar = "bar" }
> let c = C()
>
> let rawPointer = Unmanaged.passUnretained(c).toOpaque()
>

I believe that the object “c” is effectively dead from this point onwards.
Did you try putting a use of c later on to guarantee its lifetime? E.g. add
a `dump(c)` at the bottom of your script?

> let pointer = rawPointer.bindMemory(to: C.self, capacity: 1)
> let pointee = pointer.pointee
> print(pointee.foo) // EXC_BAD_ACCESS
>
> Here's some LLDB output, which looks strange to me as everything seems
> alright in pointer until I ask for its pointee:
>
> (lldb) frame variable -L c
> scalar: (memtest2.C) c = 0x0000000101d00030 {
> 0x0000000101d00040: foo = 42
> 0x0000000101d00048: bar = "bar"
> }
> (lldb) frame variable -L rawPointer
> 0x00000001005e2e08: (UnsafeMutableRawPointer) rawPointer = {
> scalar: _rawValue = 0x0000000101d00030 {
> 0x0000000101d00040: foo = 42
> 0x0000000101d00048: bar = "bar"
> }
> }
> (lldb) frame variable -L pointer
> 0x00000001005e2e10: (UnsafeMutablePointer<memtest2.C>)
> pointer = 0x0000000101d00030
> (lldb) frame variable -L pointer._rawValue
> scalar: (memtest2.C) pointer._rawValue = 0x0000000101d00030 {
> 0x0000000101d00040: foo = 42
> 0x0000000101d00048: bar = "bar"
> }
> (lldb) frame variable -L pointee
> 0x00000001005e2e18: (memtest2.C) pointee = 0x00000001005b65d8 {
> 0x00000001005b65e8: foo = 140736790071664
> 0x00000001005b65f0: bar = ""
> }
>
> I've also tried assumingMemoryBound(to:) or simply doing:
>
> let pointer = UnsafePointer<C>(bitPattern: Int(bitPattern: rawPointer))!
> print(pointer.pointee.foo) // EXC_BAD_ACCESS
>
> But I always get this EXC_BAD_ACCESS error. What is going on here?
>
>
> Thanks for your help,
> Nick
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

[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

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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users