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 theOTHER_LDFLAGS
build setting.
(emphasis mine)