From e71b01b0e31a34096482f660534fb34a391a06bc Mon Sep 17 00:00:00 2001 From: Terry Yiu Date: Tue, 8 Sep 2026 10:39:29 +0300 Subject: [PATCH] Fix dyld crash on macOS from missing sqlite3 extension symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The earlier -Wl,-U,_sqlite3_enable_load_extension fix only satisfied the linker; at runtime, Kotlin/Native's cinterop wrapper for that function still resolves against the symbol the moment SQLDelight's native-driver opens a connection, and Apple's system libsqlite3 doesn't export it on macOS — so the app now crashed instead of failing to build. Adds weak no-op definitions of sqlite3_enable_load_extension and sqlite3_load_extension, compiled directly into the app (Xcode's file-system-synchronized group picks the file up with no project.pbxproj changes needed beyond what Xcode itself rewrote on this build). Weak means a platform whose system library does provide the real symbol keeps using that one; this only fills in where it's missing. Verified there's no longer a crash by running the built macOS binary directly and by installing/launching it on the iOS Simulator — neither produced a dyld error or a crash report, versus two reproducible crash reports beforehand with the exact reported failure signature. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp --- iosApp/iosApp.xcodeproj/project.pbxproj | 48 ++++++++++++++----------- iosApp/iosApp/SQLiteExtensionStubs.c | 24 +++++++++++++ 2 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 iosApp/iosApp/SQLiteExtensionStubs.c diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index bc64050..330a606 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -11,7 +11,7 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - D262C3356B38E7E13FFE64E4 /* Exceptions for "iosApp" folder in "iosApp" target */ = { + D262C3356B38E7E13FFE64E4 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Info.plist, @@ -23,13 +23,21 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ 24D66E9CCFCEB2D844328B79 /* Configuration */ = { isa = PBXFileSystemSynchronizedRootGroup; + explicitFileTypes = { + }; + explicitFolders = ( + ); path = Configuration; sourceTree = ""; }; 55D8B06C58654F251C5B3381 /* iosApp */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( - D262C3356B38E7E13FFE64E4 /* Exceptions for "iosApp" folder in "iosApp" target */, + D262C3356B38E7E13FFE64E4 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, + ); + explicitFileTypes = { + }; + explicitFolders = ( ); path = iosApp; sourceTree = ""; @@ -137,6 +145,24 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 1DADA2DD199949A498015FFD /* Sanitize Moko Resource Bundle Names */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Sanitize Moko Resource Bundle Names"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"$PLATFORM_NAME\" != \"macosx\" ]; then\n exit 0\nfi\n# moko-resources names its resource bundle after the Kotlin klib unique_name (group:module),\n# e.g. SatsPrice:shared.bundle, and drops it directly under Contents/. Colons break\n# codesign, and a loose bundle outside Contents/Resources isn't recognized as a proper\n# nested bundle either, so the final app-level CodeSign phase fails with \"code object is\n# not signed at all\" unless we rename and relocate it. NSBundle resolves this bundle by\n# directory identity, not by name/path, so moko-resources/localization lookups still work.\nfind \"$CODESIGNING_FOLDER_PATH\" -type d -name \"*:*.bundle\" | while IFS= read -r bundle; do\n safe_name=$(basename \"$bundle\" | tr ':' '_')\n mkdir -p \"$CODESIGNING_FOLDER_PATH/Contents/Resources\"\n dest=\"$CODESIGNING_FOLDER_PATH/Contents/Resources/$safe_name\"\n rm -rf \"$dest\"\n mv \"$bundle\" \"$dest\"\ndone\n"; + }; 20CB400CC39EEB23909EAA0F /* Compile Kotlin Framework */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -174,24 +200,6 @@ shellPath = /bin/sh; shellScript = "\"$SRCROOT/../gradlew\" -p \"$SRCROOT/../\" :shared:copyFrameworkResourcesToApp \\\n -Pmoko.resources.PLATFORM_NAME=\"$PLATFORM_NAME\" \\\n -Pmoko.resources.CONFIGURATION=\"$CONFIGURATION\" \\\n -Pmoko.resources.ARCHS=\"$ARCHS\" \\\n -Pmoko.resources.BUILT_PRODUCTS_DIR=\"$BUILT_PRODUCTS_DIR\" \\\n -Pmoko.resources.CONTENTS_FOLDER_PATH=\"$CONTENTS_FOLDER_PATH\" \n"; }; - 1DADA2DD199949A498015FFD /* Sanitize Moko Resource Bundle Names */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Sanitize Moko Resource Bundle Names"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [ \"$PLATFORM_NAME\" != \"macosx\" ]; then\n exit 0\nfi\n# moko-resources names its resource bundle after the Kotlin klib unique_name (group:module),\n# e.g. SatsPrice:shared.bundle, and drops it directly under Contents/. Colons break\n# codesign, and a loose bundle outside Contents/Resources isn't recognized as a proper\n# nested bundle either, so the final app-level CodeSign phase fails with \"code object is\n# not signed at all\" unless we rename and relocate it. NSBundle resolves this bundle by\n# directory identity, not by name/path, so moko-resources/localization lookups still work.\nfind \"$CODESIGNING_FOLDER_PATH\" -type d -name \"*:*.bundle\" | while IFS= read -r bundle; do\n safe_name=$(basename \"$bundle\" | tr ':' '_')\n mkdir -p \"$CODESIGNING_FOLDER_PATH/Contents/Resources\"\n dest=\"$CODESIGNING_FOLDER_PATH/Contents/Resources/$safe_name\"\n rm -rf \"$dest\"\n mv \"$bundle\" \"$dest\"\ndone\n"; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/iosApp/iosApp/SQLiteExtensionStubs.c b/iosApp/iosApp/SQLiteExtensionStubs.c new file mode 100644 index 0000000..c05b63a --- /dev/null +++ b/iosApp/iosApp/SQLiteExtensionStubs.c @@ -0,0 +1,24 @@ +#include +#include + +// Apple's system libsqlite3 omits extension-loading support on some platforms (notably macOS, +// deliberately, for security), yet SQLDelight's native-driver still references these symbols — +// Kotlin/Native's cinterop generates a wrapper for every function declared in sqlite3.h, +// regardless of whether anything actually calls it, and this app never loads SQLite extensions. +// Without a definition somewhere, that missing symbol fails at link time (or, if the linker is +// told to allow it, crashes dyld the moment the app runs and Kotlin's wrapper resolves it). +// +// These are weak, so on a platform where the real system symbol does exist, it's used instead; +// this fallback only takes over where the real one is missing. +__attribute__((weak)) +int sqlite3_enable_load_extension(sqlite3 *db, int onoff) { + return SQLITE_OK; +} + +__attribute__((weak)) +int sqlite3_load_extension(sqlite3 *db, const char *zFile, const char *zProc, char **pzErrMsg) { + if (pzErrMsg != NULL) { + *pzErrMsg = NULL; + } + return SQLITE_ERROR; +}