Small Workaround for Crashing AU Plugins

I’ve got some plugins that are crashing below because the presets array is nullptr even after they report a size of 8. Adding a nullptr check seems to fix the problem:
in juce_AudioUnitPluginFormat.mm from line 1207

    int getNumPrograms() override
    {
        CFArrayRef presets;
        UInt32 sz = sizeof (CFArrayRef);
        int num = 0;

        if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets,
                                  kAudioUnitScope_Global, 0, &presets, &sz) == noErr)
        {
            if (presets != nullptr)
            {
                num = (int) CFArrayGetCount (presets);
                CFRelease (presets);
            }
        }

        return num;
    }

That sounds sensible, I’ll get it added. Thanks!

1 Like

I’d like to add a fix to the opposite call, setCurrentProgram:

void setCurrentProgram (int newIndex) override
{
    AUPreset current;
    current.presetNumber = newIndex;

    CFArrayRef presets;
    UInt32 sz = sizeof (CFArrayRef);

    if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets,
                              kAudioUnitScope_Global, 0, &presets, &sz) == noErr)
    {
        if (CFArrayGetCount(presets) == 0) // <-- add this check!
            return;                   
        if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, newIndex))
            current.presetName = p->presetName;

        CFRelease (presets);
    }

    AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset,
                          kAudioUnitScope_Global, 0, &current, sizeof (AUPreset));

    sendAllParametersChangedEvents();
}

If that check for an empty preset list isn’t added, the following line will just exit silently.

Any thoughts?

Where are you seeing this crash? Might it be better to do the following, so we don’t just early-return and still call CFRelease(), sendAllParametersChangedEvents() etc.:

void setCurrentProgram (int newIndex) override
{
    AUPreset current;
    current.presetNumber = newIndex;

    CFArrayRef presets;
    UInt32 sz = sizeof (CFArrayRef);

    if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_FactoryPresets,
                              kAudioUnitScope_Global, 0, &presets, &sz) == noErr)
    {
        if (CFArrayGetCount (presets) > 0)
            if (auto* p = (const AUPreset*) CFArrayGetValueAtIndex (presets, newIndex))
                current.presetName = p->presetName;

        CFRelease (presets);
    }

    AudioUnitSetProperty (audioUnit, kAudioUnitProperty_PresentPreset,
                          kAudioUnitScope_Global, 0, &current, sizeof (AUPreset));

    sendAllParametersChangedEvents();
}

That’s fine with me, thanks. Steps to reproduce this crash: use the JUCE plugin host, load an Audio Unit that has no programs (e.g. Gulfoss by Soundtheory). Calling getCurrentProgram() returns 0, but setCurrentProgram(0) leads to that crash. One could argue that it’s stupid to set a program when there are no programs, but still, it shouldn’t crash.

Thanks for confirmiing, this is on develop now:

1 Like