Ian Bytchek Ian Bytchek - 20 days ago 6
Swift Question

Call C function from Swift knowing only memory address

I have a very simple function in C and its pointer gets passed into Swift.

void callback() {
NSLog(@"such pointer…");
}


How can it be invoke in Swift using ONLY the pointer? This is NOT about simply invoking it – it works fine when invoked directly. Tried the following and different variations with signature casting, but it always crashes:

let pointer: UnsafePointer<@convention(c)() -> ()> = UnsafePointer(bitPattern: …)
let callback: @convention(c)() -> () = pointer.memory
Swift.print(callback) // (Function)
callback() // Handling crash with signal 11...


Tried defining
Callback
type with
typedef void(*Callback)();
– same thing:

let pointer: UnsafePointer<Callback> = UnsafePointer(bitPattern: …)
let callback: Callback = pointer.memory
Swift.print(callback) // (Function)
callback() // Handling crash with signal 11...


To check that it actually works and points to the right address I have another Objective-C function, which works as expected when invoked from Swift with the callback pointer.

void invokeCallback(uintptr_t callback) {
((void (*)()) callback)(); // such pointer…
}

Answer

The same approach as in Swift: How to call a C function loaded from a dylib should work here.

Example for Swift 3 (assuming that funcPtr is a UnsafeRawPointer containing the function's address):

// Define function type:
typealias callbackFunc = @convention(c) () -> Void

// Convert pointer to function type:
let callback = unsafeBitCast(funcPtr, to: callbackFunc.self)

// Call function:
callback()

Of course the type alias must match the actual function signature, and the function needs to be a "pure" C function (not an Objective-C method).

Comments