Crash running app build on macOS 13.6 (clang 15), when running on macOS 11 (dynamic_cast)

Have an issue that started when I upgraded xcode to 15 on a build server.

Apps that are linking against binaries build “some time ago” ™ – now crash when run on macOS11 or earlier. The same binary runs fine on on macos12/13/14.

The culprit is any dynamic_cast, a simplified example is shown below (minimal single file app that has same fault):

OS target is: 10.14
c++ dialect is: C++11 (-std=c++11 … same as the old libraries I’m linking against)

#import "AppDelegate.h"

#import <osg/AnimationPath>
#import <osg/ref_ptr>

/*
 Define some subclass of osg::AnimationPath, so we have something to downcast to
 */
class PanZoomAnimationPath : public osg::AnimationPath {
public:
    PanZoomAnimationPath() {
        setLoopMode(osg::AnimationPath::NO_LOOPING);
    }
};


@interface AppDelegate () {
    osg::ref_ptr<osg::AnimationPath>  _animationPath;
}

@property (strong) IBOutlet NSWindow *window;

@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Try to do some dynamic cast
    
//    auto createdPath = new osg::AnimationPath();
    auto createdPath = new PanZoomAnimationPath();
    
    // shove into a ref_ptr that is on the class
    _animationPath = createdPath;

    NSLog(@"Ptr to path: %p", createdPath);
    NSLog(@"Ptr from _animationPath: %p", _animationPath.get());
    NSLog(@"Animation path ptr is: %p. Is it valid: %d", _animationPath.get(), _animationPath.valid());
    
    // try to dynamic cast. BOOM (at least, on macOS 11)
    PanZoomAnimationPath *pStudioPath = dynamic_cast<PanZoomAnimationPath * >(_animationPath.get());
    if(pStudioPath) {
        NSLog(@"Success!");
    } else {
        NSLog(@"createdPath is not of type PanZoomAnimationPath");
    }
}

@end

When run on macOS13/14, this works and produces the right output, correctly downcasting and either being NULL or not depending on the pointer.

On macOS11 if fails (segfault 11)

Here’s the stack trace:

Path:                  /Users/USER/TestOld.app/Contents/MacOS/TestOld
Identifier:            com.shinywhitebox.TestOld
Version:               1.0 (1)
Code Type:             X86-64 (Native)
Parent Process:        bash [62750]
User ID:               504

Date/Time:             2023-09-28 20:50:19.100 +1300
OS Version:            macOS 11.7.8 (20G1351)
Report Version:        12
Anonymous UUID:        86319E29-4169-27B2-C19A-1C7378984637

Sleep/Wake UUID:       D03F977E-2B4B-443D-8EB9-8478E632ECBD

Time Awake Since Boot: 790000 seconds
Time Since Wake:       1500 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000007e6b008
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [63209]

VM Regions Near 0x7e6b008:
--> 
    __TEXT                      107e6b000-107e73000    [   32K] r-x/r-x SM=COW  /Users/*/TestOld.app/Contents/MacOS/TestOld

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libc++abi.dylib                 0x00007fff20543d16 __dynamic_cast + 393
1   com.shinywhitebox.TestOld       0x0000000107e6ea2f -[AppDelegate applicationDidFinishLaunching:] + 255
2   com.apple.CoreFoundation        0x00007fff2066d463 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
3   com.apple.CoreFoundation        0x00007fff20708ed9 ___CFXRegistrationPost_block_invoke + 49
4   com.apple.CoreFoundation        0x00007fff20708e54 _CFXRegistrationPost + 496
5   com.apple.CoreFoundation        0x00007fff2063e6ce _CFXNotificationPost + 736
6   com.apple.Foundation            0x00007fff213b1c18 -[NSNotificationCenter postNotificationName:object:userInfo:] + 59
7   com.apple.AppKit                0x00007fff22e88d80 -[NSApplication _postDidFinishNotification] + 305
8   com.apple.AppKit                0x00007fff22e88ad2 -[NSApplication _sendFinishLaunchingNotification] + 208
9   com.apple.AppKit                0x00007fff22e85c71 -[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] + 541
10  com.apple.AppKit                0x00007fff22e858c7 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 665
11  com.apple.Foundation            0x00007fff213dd366 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 308
12  com.apple.Foundation            0x00007fff213dd1d6 _NSAppleEventManagerGenericHandler + 80
13  com.apple.AE                    0x00007fff2645b853 0x7fff2644f000 + 51283
14  com.apple.AE                    0x00007fff2645af6e 0x7fff2644f000 + 49006
15  com.apple.AE                    0x00007fff26453cd3 aeProcessAppleEvent + 448
16  com.apple.HIToolbox             0x00007fff288d3012 AEProcessAppleEvent + 54
17  com.apple.AppKit                0x00007fff22e7ff70 _DPSNextEvent + 2046
18  com.apple.AppKit                0x00007fff22e7e2a5 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1364
19  com.apple.AppKit                0x00007fff22e705c9 -[NSApplication run] + 586
20  com.apple.AppKit                0x00007fff22e447cc NSApplicationMain + 816
21  com.shinywhitebox.TestOld       0x0000000107e6e81f main + 47
22  libdyld.dylib                   0x00007fff2059af3d start + 1

Thread 1:: Dispatch queue: com.apple.CFVolumeObserver.0x7fad90e1fe60

When run from macOS 14, you get:

Ptr from _animationPath: 0x60000039a7d0
Animation path ptr is: 0x60000039a7d0. Is it valid: 1
Success!

From macOS11:

2023-09-28 21:10:10.997 TestOld[63675:8470300] Ptr from _animationPath: 0x7fe879e2c3b0
2023-09-28 21:10:10.997 TestOld[63675:8470300] Animation path ptr is: 0x7fe879e2c3b0. Is it valid: 1
Segmentation fault: 11

I’ve tried recompiling the old libraries as well, and this hasn’t worked. It crashes on different dynamic_casts.

I’m no expert at ABI related issues, so asking for any help / pointers here.

This is due to a change in the linker in Xcode 15. It’s documented in the release notes but it’s easy to miss and not easy to find if you don’t know where to look. You’d think they’d add a build-time warning when your project contains affected symbols and targets older macOS versions…

Anyway, the release notes also document a work-around:

Binaries using symbols with a weak definition crash at runtime on iOS 14/macOS 12 or older. This impacts primarily C++ projects due to their extensive use of weak symbols. (114813650) (FB13097713)

Workaround: Bump the minimum deployment target to iOS 15, macOS 12, watchOS 8 or tvOS 15, or add -Wl,-ld_classic to the OTHER_LDFLAGS build setting.

(emphasis mine)

Leave a Comment