Problem calling a C function passing a void** from Swift 3


(Lane Schwartz) #1

Hi,

I just moved to Xcode 8 (actually, it upgraded itself without me realizing
it, but anyway), and some previously working Swift 2.2 code now doesn't
work. I'm having trouble migrating.

The code in question is supposed to declare, but not allocate, a block of
memory. A void** to that block of memory was then passed to a C function
(cudaMalloc to be specific) which then allocated memory on the GPU. The
swift 2.2 code that worked was like this:

var data_on_device : UnsafeMutablePointer<Void>

...

self.byteCount = count * sizeof(CFloat)

self.data_on_device = nil

let status = cudaMalloc(&data_on_device, self.byteCount)

Then elsewhere in the code I would convert this pointer to its appropriate
typed version:

UnsafeMutablePointer<Float>(foo.data_on_device)

Can anyone help me get the equivalent functionality in Swift 3?

The closest I've been able to come is the following, which (a) was very
non-obvious and took a lot of trial and error to find, and (b) is ugly.

var data_on_device : UnsafeMutablePointer<Float>

let data_on_device_void_pointer : UnsafeMutableRawPointer
...
self.byteCount = count * MemoryLayout<Float>.size
self.data_on_device = UnsafeMutablePointer<Float>.allocate(capacity:0)
self.data_on_device_void_pointer = UnsafeMutableRawPointer(data_on_device)
var pointer_as_optional : UnsafeMutableRawPointer? =
data_on_device_void_pointer
let pointer : UnsafeMutablePointer<UnsafeMutableRawPointer?> =
UnsafeMutablePointer<UnsafeMutableRawPointer?>(&pointer_as_optional)
let status = cudaMalloc(pointer, self.byteCount)

For reference, the code and git history is here:
https://github.com/dowobeha/mt-marathon-swift-c/blob/master/main.swift

Thanks,
Lane


(Quinn “The Eskimo!”) #2

I think the main issue here is that, in Swift 3, unsafe pointers, in their various flavours, don’t explicitly support nil. Rather, nil is modelled like it is for any other type, via `Optional`. You can read all about this change in SE-0055 [1]

So, if you have an C API like this:

extern int HackAlloc(void ** bufPtrPtr, size_t bufSize);
extern void HackFree(void * bufPtr);

you can call it like this:

var buf: UnsafeMutableRawPointer? = nil
let result = HackAlloc(&buf, 1024)
if result == 0 {
    HackFree(buf)
}

This is very similar to what you currently have except that `buf` is explicitly made optional.

The other difference is that `buf` is a ‘raw’ pointer, which means you have to understand Swift 3’s type aliasing rules. You can read about the details in SE-0107 [2] bug a good place to start is the “UnsafeRawPointer Migration” section of the Swift 3 migration guide.

<https://swift.org/migration-guide/se-0107-migrate.html>

Share and Enjoy

···

On 15 Sep 2016, at 22:11, Lane Schwartz via swift-users <swift-users@swift.org> wrote:

Can anyone help me get the equivalent functionality in Swift 3?

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1]: <https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md>

[2]: <https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md>


(Lane Schwartz) #3

Thank you! This, in conjunction with a later call to bindMemory(to:
capacity:), was exactly what I needed.

···

On Fri, Sep 16, 2016 at 9:47 AM, Quinn "The Eskimo!" via swift-users < swift-users@swift.org> wrote:

On 15 Sep 2016, at 22:11, Lane Schwartz via swift-users < > swift-users@swift.org> wrote:

> Can anyone help me get the equivalent functionality in Swift 3?

I think the main issue here is that, in Swift 3, unsafe pointers, in their
various flavours, don’t explicitly support nil. Rather, nil is modelled
like it is for any other type, via `Optional`. You can read all about this
change in SE-0055 [1]

So, if you have an C API like this:

extern int HackAlloc(void ** bufPtrPtr, size_t bufSize);
extern void HackFree(void * bufPtr);

you can call it like this:

var buf: UnsafeMutableRawPointer? = nil
let result = HackAlloc(&buf, 1024)
if result == 0 {
    HackFree(buf)
}

This is very similar to what you currently have except that `buf` is
explicitly made optional.

The other difference is that `buf` is a ‘raw’ pointer, which means you
have to understand Swift 3’s type aliasing rules. You can read about the
details in SE-0107 [2] bug a good place to start is the “UnsafeRawPointer
Migration” section of the Swift 3 migration guide.

<https://swift.org/migration-guide/se-0107-migrate.html>

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1]: <https://github.com/apple/swift-evolution/blob/master/
proposals/0055-optional-unsafe-pointers.md>

[2]: <https://github.com/apple/swift-evolution/blob/master/proposals/0107-
unsaferawpointer.md>

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

--
When a place gets crowded enough to require ID's, social collapse is not
far away. It is time to go elsewhere. The best thing about space travel
is that it made it possible to go elsewhere.
                -- R.A. Heinlein, "Time Enough For Love"