NSData and UnsafePointer


(J.E. Schotsman) #1

A mysterious bug has got me thinking about using UnsafePointer<CChar> with NSData (Swift 2).

Is this safe:

let data:NSData = …
let dataStart = UnsafePointer<CChar>(data:NSDAta.bytes)

myProcessdata1(dataStart,data.length)

… (no more references to data)

And this:

let data:NSData = …
myProcessdata2(data)

… (no more references to data)

func myProcessdata2( data:NSData )
{
let dataStart = UnsafePointer<CChar>(data:NSData.bytes)
myProcessdata1(dataStart,data.length)
}

In the latter case I would hope that data remains alive until the function myProcessdata2 returns. But does it?

TIA,

Jan E.


(Andrew Trick) #2

A mysterious bug has got me thinking about using UnsafePointer<CChar> with NSData (Swift 2).

Is this safe:

let data:NSData = …
let dataStart = UnsafePointer<CChar>(data:NSDAta.bytes)

myProcessdata1(dataStart,data.length)

… (no more references to data)

I don’t know what the recommended idiom is or if the syntax has changed from Swift 2 to 3, but I would do something like this:

withExtendedLifetime(data) {
  let dataStart = UnsafePointer<CChar>(data.bytes)
  myProcessdata1(dataStart,data.length)
}

UnsafePointers aren’t meant to keep things alive.

There’s also the problem of potentially casting your UnsafePointer to something other than CChar, but that’s not really the issue at hand.

And this:

let data:NSData = …
myProcessdata2(data)

… (no more references to data)

func myProcessdata2( data:NSData )
{
let dataStart = UnsafePointer<CChar>(data:NSData.bytes)
myProcessdata1(dataStart,data.length)
}

In the latter case I would hope that data remains alive until the function myProcessdata2 returns. But does it?

I think the latter case has the same problems as the former.

-Andy

···

On Jul 16, 2016, at 5:28 AM, J.E. Schotsman via swift-users <swift-users@swift.org> wrote:

TIA,

Jan E.

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


(Dmitri Gribenko) #3

This is exactly the reason why Swift 3 changes this API to use the
`data.withUnsafe* {}` idiom.

Dmitri

···

On Sat, Jul 16, 2016 at 1:16 PM, Andrew Trick via swift-users <swift-users@swift.org> wrote:

On Jul 16, 2016, at 5:28 AM, J.E. Schotsman via swift-users <swift-users@swift.org> wrote:

A mysterious bug has got me thinking about using UnsafePointer<CChar> with NSData (Swift 2).

Is this safe:

let data:NSData = …
let dataStart = UnsafePointer<CChar>(data:NSDAta.bytes)

myProcessdata1(dataStart,data.length)

… (no more references to data)

I don’t know what the recommended idiom is or if the syntax has changed from Swift 2 to 3, but I would do something like this:

withExtendedLifetime(data) {
  let dataStart = UnsafePointer<CChar>(data.bytes)
  myProcessdata1(dataStart,data.length)
}

UnsafePointers aren’t meant to keep things alive.

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(J.E. Schotsman) #4

I tried that but got a compiler crash (segmentation fault 11)
So I improvised my own withExtendedLifetime by extending NSData with a doNothing() method which sets a field in a global struct.

let dataStart = UnsafePointer<CChar>(data.bytes)
myProcessdata1(dataStart,data.length)
data.doNothing()

but this didn’t help. Apparently this is not a lifetime bug.

The code that crashed looked like this:

init() throws
  {
  let data = ...
  do { try withExtendedLifetime(data)
    {
    let ptr = UnsafePointer<Int8>(data.bytes)
    do { try super.init(dataPtr:ptr, dataLength: data.length) ) }
    }}
  }

Calling super.init in a closure is probably illegal anyway.

I wonder, would Whole Module Optimization notice that doNothing() does nothing (i.e. the field in the global struct is never read) and remove it?

Jan E.

···

On 16 Jul 2016, at 22:16, Andrew Trick <atrick@apple.com> wrote:

I don’t know what the recommended idiom is or if the syntax has changed from Swift 2 to 3, but I would do something like this:

withExtendedLifetime(data) {
let dataStart = UnsafePointer<CChar>(data.bytes)
myProcessdata1(dataStart,data.length)
}