Skip to content

Commit 58f1df5

Browse files
committed
fix(bridge): defer dylib init off the constructor (macOS 26 dyld init-order)
Move all ObjC/Foundation/IMCore work out of the __attribute__((constructor)) into a bridgeBootstrap() dispatched on the main queue. macOS 26 tightened dyld initializer ordering for platform apps; touching Foundation at constructor time can run before libSystem finishes bootstrapping and abort Messages on launch. The constructor now only enqueues (a libdispatch call, no synchronous ObjC). Based on v0.11.0; constructor change only.
1 parent c3205e1 commit 58f1df5

1 file changed

Lines changed: 16 additions & 2 deletions

File tree

Sources/IMsgHelper/IMsgInjected.m

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4371,8 +4371,13 @@ static void startV2InboxWatcher(void) {
43714371

43724372
#pragma mark - Dylib Entry Point
43734373

4374-
__attribute__((constructor))
4375-
static void injectedInit(void) {
4374+
// Bridge bootstrap. Intentionally NOT run from the dylib constructor: macOS 26
4375+
// tightened dyld initializer ordering for platform/system apps, so touching
4376+
// ObjC/Foundation/IMCore at constructor time can execute before libSystem has
4377+
// finished bootstrapping ("dyld initialized but libSystem has not") and abort
4378+
// Messages.app on launch. injectedInit() defers this onto the main queue, which
4379+
// only drains once the process is fully initialized.
4380+
static void bridgeBootstrap(void) {
43764381
NSLog(@"[imsg-bridge] Dylib injected into %@", [[NSProcessInfo processInfo] processName]);
43774382

43784383
// Connect to IMDaemon for full IMCore access
@@ -4413,6 +4418,15 @@ static void injectedInit(void) {
44134418
});
44144419
}
44154420

4421+
__attribute__((constructor))
4422+
static void injectedInit(void) {
4423+
// Keep the constructor tiny: only enqueue onto the main queue (a libdispatch
4424+
// call, no synchronous ObjC message dispatch). All ObjC/Foundation/IMCore
4425+
// work happens later in bridgeBootstrap, after the runloop is live — see the
4426+
// comment there for the macOS 26 dyld init-order rationale.
4427+
dispatch_async(dispatch_get_main_queue(), ^{ bridgeBootstrap(); });
4428+
}
4429+
44164430
__attribute__((destructor))
44174431
static void injectedCleanup(void) {
44184432
NSLog(@"[imsg-bridge] Cleaning up...");

0 commit comments

Comments
 (0)