I’m trying to integrate the VICE emulator’s libretro core (vice_x64sc_libretro_ios.dylib) into my iOS app using Swift. The core provides a function retro_load_game
that I load dynamically using dlsym()
. However, when I try to call this function, I get a crash (EXC_BAD_ACCESS
).
From the VICE emulator source code, the function I’m trying to call is defined as:
bool retro_load_game(const struct retro_game_info *game);
The retro_game_info
struct is defined as:
struct retro_game_info {
const char *path; // UTF-8 encoded file path
const void *data; // Memory buffer of the game file (NULL if fullpath mode is used)
size_t size; // Size of the memory buffer
const char *meta; // Meta information (NULL if not used)
};
I load the .dylib, get a pointer to retro_load_game
, and then call it with a properly allocated retro_game_info
struct:
import UIKit
class ViewController: UIViewController {
var core: UnsafeMutableRawPointer?
override func viewDidLoad() {
super.viewDidLoad()
setupEmulator()
}
func setupEmulator() {
let corePath = Bundle.main.bundlePath + "/Frameworks/vice_x64sc_libretro_ios.dylib"
if FileManager.default.fileExists(atPath: corePath) {
core = dlopen(corePath, RTLD_LAZY)
if core == nil {
return
}
if let filePath = Bundle.main.path(forResource: "SomePrg", ofType: "prg") {
loadGame(filePath)
}
}
}
func loadGame(_ filePath: String) {
guard let core = self.core else {
return
}
if let retroLoadGamePtr = dlsym(core, "retro_load_game") {
typealias RetroLoadGameFunc = @convention(c) (UnsafeRawPointer?) -> Int32
let retroLoadGame = unsafeBitCast(retroLoadGamePtr, to: RetroLoadGameFunc.self)
if let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) {
let pathCString = strdup(filePath)
let dataPointer = malloc(fileData.count)
if let pathCString = pathCString, let dataPointer = dataPointer {
fileData.copyBytes(to: dataPointer.assumingMemoryBound(to: UInt8.self), count: fileData.count)
var gameInfo = retro_game_info(
path: pathCString,
data: dataPointer,
size: fileData.count,
meta: nil
)
let result = retroLoadGame(UnsafeRawPointer(&gameInfo)) // Crashes here
free(pathCString)
free(dataPointer)
}
}
}
}
}
struct retro_game_info {
let path: UnsafePointer<CChar>?
let data: UnsafeRawPointer?
let size: size_t
let meta: UnsafePointer<CChar>?
}
I get EXC_BAD_ACCESS (code=1, address=0x0)
at:
let result = retroLoadGame(UnsafeRawPointer(&gameInfo))
I have checked:
dlopen()
successfully loads the .dylibdlsym()
successfully findsretro_load_game
gameInfo.path
andgameInfo.data
are allocated before callingretro_load_game
- I free allocated memory after the function call
So:
- Is my Swift
retro_game_info
struct correctly matching the C struct? - Is
UnsafeRawPointer(&gameInfo)
the right way to pass this struct toretro_load_game
? - Am I missing any memory alignment issues that could cause
EXC_BAD_ACCESS
? - Is there a better way to debug why
retro_load_game
is failing?