I’m running into a very strange crash.
The code I’m running is very trivial:
juce::MidiFile f;
auto stream = juce::MemoryInputStream(
BinaryData::Funky_midi, BinaryData::Funky_midiSize, false);
f.readFrom(stream);
Built with CMake/Xcode 15, This works fine on almost all Macs I’ve tried, but crashes in the following scenario:
Building computer is a modern Mac/Xcode 15.
Running computer is a Catalina (10.15) machine.
If I build it on the Catalina machine (Xcode 12), it works fine.
The crash also only happens in standalone, and it doesn’t crash in VST3 built the same way.
Any ideas?
I made a stripped down project showing the problem here:
In terms of the build it doesn’t matter, I got the same result by building a universal binary on Intel Macs and on M1 macs, and also by using multiple CMake generators (Ninja/Xcode/Unix Makefiles).
On the running machine, the crash happened on 3 different machines: two intel Macs running a native installation of Catalina and one (also Intel) running a VM of Catalina.
On that last intel machine the same build ran just fine using Ventura.
The crash log in all of those reports something to do with the use of std::stable_sort in juce::MidiFile::readFrom().
I will point again that even on the problematic machines, only standalone crashed, while VST3 played fine (including actually playing back the MIDI file in a different part of the code).
In terms of the build it doesn’t matter, I got the same result by building a universal binary on Intel Macs and on M1 macs, and also by using multiple CMake generators (Ninja/Xcode/Unix Makefiles).
On the running machine, the crash happened on 3 different machines: two intel Macs running a native installation of Catalina and one (also Intel) running a VM of Catalina.
On that last intel machine the same build ran just fine using Ventura.
The crash log in all of those reports something to do with the use of std::stable_sort in juce::MidiFile::readFrom().
I will point again that even on the problematic machines, only standalone crashed, while VST3 played fine (including actually playing back the MIDI file in a d
[/quote]
The value of this variable should be set prior to the first project() or enable_language() command invocation because it may influence configuration of the toolchain and flags.
In your example project you are setting it after the project call. Maybe this has something to do with it and you are building for another deployment target than assumed. This might be a reason for different behaviour depending on the build machine which might both set a different target if not specified
Sorry about that, that was an oversight in the test project that doesn’t happen in the real project.
To test, I updated the test project and git repo and changed the order of the target calls so it’s before project().
Then, I cleaned the build folder, regenerated and rebuilt - same thing.
I’m attaching the crash log, as well as a built debug version you can try yourself. It’s unsigned but the issue happens the exact same way with a version that is signed/notarized.
I tried adjusting the GuiAppExample app in the JUCE repo to call MidiFile::readFrom in the constructor of the MainComponent, and loading the problematic file from the repo you provided. Then, I built the app on macOS 14 with Xcode 15, and copied it to a computer running macOS 10.14 (I don’t have 10.15 installed anywhere at the moment).
Running the app caused a crash, but in a different place. Specifically, the app crashed while calling initialisers for global statics. After investigating a bit, I think this may be a manifestation of the issue described here:
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.
When I add -W,-ld_classic to my CMAKE_EXE_LINKER_FLAGS, I no longer see the crash.
Please could you try adding this flag to your build options and check whether the issue persists?
The crash in __cxx_global_var_init looks like what I was seeing.
Depending on when you’re calling set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -W,-ld_classic"), I think it may not apply properly due to interactions between cache and non-cache variables. Also, it looks like there’s an l missing - the flag should be -Wl,-ld_classic.
Please could you try:
deleting your build folder, and
passing -D CMAKE_EXE_LINKER_FLAGS=-Wl,-ld_classic during configuration.
Then, try running the app again and see if it still crashes.
As I understand it, this flag just enables the “old” linker, so the compile-time and run-time performance will be equivalent to using Xcode 14.
I’m not sure, but I think the issue isn’t related to BinaryData, MidiFile, or any other part of JUCE. The release notes from Apple say that
Binaries using symbols with a weak definition crash at runtime on iOS 14/macOS 12 or older.
The exact circumstances/causes of such crashes are not provided, so I’d be inclined to assume the worst; it is essentially UB to target an older platform with the new linker if the binary uses any symbol with a weak definition, i.e. the program is malformed, even if the weak symbol is not accessed at runtime. JUCE projects (and pretty much any C++ project that uses Apple frameworks) use lots of weak symbols, so I think it’s simply incorrect to use the new linker to target an older platform for such projects.
So, are there any disadvantages to switch to using that old linker? Will it hurt my performance (on new machines) in some way? Do I need to now provide two different mac installers?
Trying to understand my options here as we’ve been deploying with new linker on 10.13+ for a long time and this is the only crash we’ve ever had with it.
I don’t know. I think it’s essentially the same as using the Xcode 14 linker, which until a month ago was the latest-and-greatest, so I can’t imagine that there would be any significant downsides to using the older version.
No, products linked with Xcode 14 or with Xcode 15’s classic linker should run on newer machines with no problems afaik.
Are you sure? Xcode 15 was only released on September 18th.
From Apple’s issue description, it’s not clear whether programs are guaranteed to crash, or whether there’s just a chance of crashes. Again, I’d be inclined to assume the worst and to treat this like UB; a program that contains UB is broken, even if it appears to work in some situations.
Another option would be to stick on Xcode 14 for now, and to upgrade to Xcode 15.1 when it released, as the release notes for Xcode 15.1 beta say that this issue will be fixed there:
Ah! Sorry I misunderstood you at first, I thought you meant that this new linker has been there for a while, I didn’t realize it was an Xcode 15 thing.
Right, as long as this an Xcode 15 thing that is fixed in 15.1 we can definitely try the beta or use 14. Thanks!
Since this issue will probably hit many JUCE devs out there for a while, I would suggest that add this to public documentation somehow, or CMake docs, etc, even though this is clearly an Apple issue.
Yes, sorry about that, I just misunderstood the original comment on what the “new linker” is, I thought it meant the post Big Sur linker and not the Xcode 15 super-new-linker.