Using dlsym to load both functions and constants

I was successfully using dlsym to dynamically load and invoke functions at runtime. Now I need to load constants and for some reason unsafeBitCast fails on me, whereas assumingMemoryBound works. However, using assumingMemoryBound with a function somehow messes with it and it crashes during the invocation.

unsafeBitCast fails with constant:

import Foundation
internal typealias F = @convention(c) (_ alloc: CFAllocator?, _ cStr: UnsafePointer<UInt8>, _ encoding: CFStringEncoding) -> CFString?
func load<T>(_ name: String) -> T {
    unsafeBitCast(dlsym(dlopen(nil, RTLD_NOW), name), to: T.self)
}
print(load("CFStringCreateWithCString") as F) // (Function)
print((load("CFStringCreateWithCString") as F)(nil, [102, 111, 111, 0], CFStringBuiltInEncodings.UTF8.rawValue)!) // foo
print(load("kCFErrorLocalizedFailureKey") as CFString) // EXC_BAD_ACCESS

assumingMemoryBound fails with invocation:

import Foundation
internal typealias F = @convention(c) (_ alloc: CFAllocator?, _ cStr: UnsafePointer<UInt8>, _ encoding: CFStringEncoding) -> CFString?
func load<T>(_ name: String) -> T {
    dlsym(dlopen(nil, RTLD_NOW), name).assumingMemoryBound(to: T.self).pointee
}
print(load("kCFErrorLocalizedFailureKey") as CFString) // NSLocalizedFailure
print(load("CFStringCreateWithCString") as F) // (Function)
print((load("CFStringCreateWithCString") as F)(nil, [102, 111, 111, 0], CFStringBuiltInEncodings.UTF8.rawValue)!) // EXC_BAD_ACCESS

Can anybody explain what's going on? Is there a way to load all kinds of symbols with one declaration?

@eskimo, @NeoNacho, @mayoff, you guys posted some great answers on these matter. May I kindly ask for your input?

A function symbol generally resolves to the entry point of the function, which in C would be a function pointer type, or in Swift a @convention(c) function type. A data symbol generally resolves to the address of the data, not the data itself, so you probably want to resolve kCFErrorLocalizedFailureKey as an UnsafePointer<CFString> and load the CFString from the pointer.

1 Like

Argh! Brilliant! Thanks you very much!

You say generally. Is that the rule or might there be exceptions? Are there any other things to keep in mind when dlsym'ing things?

Well, there are also "absolute symbols" whose value can directly encode a pointer-sized integer value, but you're unlikely to encounter them in practice.

2 Likes