Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2015-11-12

Swift gotcha: UnsafePointer and UnsafeMutablePointer

The UnsafePointer and the UnsafeMutablePointer seem similar enough, but really, they're not!

The first and most obvious difference is that for the UnsafeMutablePointer you need to use the ampersand "&" to refer to an address, with the UnsafePointer that is optional. While annoying for a language purist, the compiler will warn you, so this is not a big issue.

What may bite you is the difference and similarity between indexed pointers of both types, i.e. &buf[2] when you use them as arguments. Mutable pointer will put the address of the third buffer element in the argument, while for non-mutable pointers the third buffer element is copied to a new memory area and a pointer to that area is passed. In the later case losing access to the rest of the buffer.

The work around for these kind of problems is to never use the &buf[iconstruction but the &buf+which has the same behaviour for both types of pointers.

Associated example code:

func non(a: UnsafePointer<UInt8>) {
    print("non address = \(a), content = \(a.memory), content + 1 = \((a+1).memory)")
}

func mut(a: UnsafeMutablePointer<UInt8>) {
    print("mut address = \(a), content = \(a.memory), content + 1 = \((a+1).memory)")
}

var buf: Array<UInt8> = [1, 2, 3, 4, 5]

non(buf)
non(&buf)
mut(&buf)

print("---")

non(&buf[2])
mut(&buf[2])

print("---")

non(&buf+2)
mut(&buf+2)

Output:

non address = 0x00007f84f1e01f30, content = 1, content + 1 = 2
non address = 0x00007f84f1e01f30, content = 1, content + 1 = 2
mut address = 0x00007f84f1e01f30, content = 1, content + 1 = 2
---
non address = 0x00007fff5af70f40, content = 3, content + 1 = 15
mut address = 0x00007f84f1e01f32, content = 3, content + 1 = 4
---
non address = 0x00007f84f1e01f32, content = 3, content + 1 = 4
mut address = 0x00007f84f1e01f32, content = 3, content + 1 = 4

PS: I have reported this to apple, the above behaviour is for Swift 2.1 and Xcode 7.1. Apple replied that this is the intended result because we are not supposed to add to the UnsafePointer. While I can live with that, I still don't like the fact that the same syntax produces different results without generating warnings. This is a vulnerability that could cause big problems when maintaining existing code.

Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment