tldr: Using CMake and the Ninja generator when building AAX plug-ins causes all of JUCE’s symbols to be exported causing subtle bugs due to symbol clashes with an internal ProTools plug-in which is also built with JUCE.
Long version:
We’ve recently been observing a strange issue with AAX plug-ins built by JUCE causing very subtle bugs in recent development versions of ProTools. For example, the code of one of my clients, crashes while loading in ProTools due to juce::emptyString being de-allocated - this should never happen as juce::emptyString is a global variable.
The root cause took a while to figure out: it turns out that there are two copies of JUCE in the process address space of ProTools: one from my client’s plug-in - let’s call this JUCE A - and the other inside one of ProTool’s internal AAX plug-ins which is also using JUCE - let’s call this JUCE B.
Our crash occurs because, in JUCE A &juce::var::VariantType::defaultToString is assigned to the juce::var::VariantType::toString function pointer at runtime. However, this resolves to the function juce::var::VariantType::defaultToString of JUCE B. The defaultToString returns an empty string which is simply a reference to the global variable juce::emptyString. In the above case, it will return a pointer to JUCE B’s copy of juce::emptyString.
On string de-allocation, JUCE compares the pointer to juce::emptyString and if it is equal, it will skip de-allocation, which is the correct behaviour, as juce::emptyString is a global. However, in the above crash, JUCE A now compares the pointer (coming from juce::emptyString of JUCE B) with juce::emptyString of JUCE A, which is not equal, and JUCE will try to de-allocate the string.
Note however, that the crash manifests itself in many different ways for different plug-ins. The above is just an example. The crash usually turns up in ValueTree or OpenGL related code as both make extensive use of function pointers which are resolved at runtime.
Of course, neither my client’s plug-in nor any ProTools internal plug-ins should be exporting JUCE symbols. In fact, the only thing that should be exported are the AAX entry points (and a single JUCE symbol related to accessibility).
We’ve narrowed down the bug to JUCE’s cmake support. If the AAX is built with CMake and ninja then the AAX will export all of JUCE’s symbols. This can easily be checked with the following command:
nm --defined-only --extern-only "MyAAXPlugin.aaxplugin/Contents/MacOS/MyAAXPlugin"| grep " T " | grep juce | c++filt
If the above command lists a bunch of JUCE symbols (instead of a single accessibility JUCE symbol) then the AAX wasn’t linked correctly and you are likely going to run into this issue.
Interestingly, building the same AAX with CMake but using the XCode generator fixes the issue.
Any help would be appreciated! Once this issue is fixed we need to reach out to Avid so that they fix their internal plug-in. As no plug-in should be exporting JUCE symbols.
