[BUG] JUCE 6 crashes on VST3 delete with open windows, JUCE 5 does not

Could someone from the JUCE team please take a look at this? I’m having a problem with my VST3 crashing on delete now that I have moved to JUCE 6.

I created this very simple audio plugin project to demonstrate what appears to be a bug in JUCE 6.01:

PluginWithWindow.zip (27.6 KB)

In AudioPluginHost, deleting this filter (VST3) with the editor windows open will crash in [NSApp run] (which is I guess Mac stuff). I cannot get anywhere with debugging this.

This does not happen in JUCE 5.4.7. Also, no problem with VST and AU. Just VST3. I am running Mojave 10.14.6, Xcode 10.3.

This is a default audio plugin project. The only thing I have modified is the PluginEditor.cpp and PluginEditor.h files.

I added a second window that can be opened by a button in the main window.

Steps:

Instantiate the plugin in AudioPluginHost 6.0.1.
Delete using right-click popup menu. OK.

Instantiate plugin
Double-click to open Editor.
Delete using right-click popup menu. OK.

Instantiate plugin
Double-click to open Editor.
Click “Open Window 2” button to open second window.
Close second Window using its close button.
Delete using right-click popup menu. OK.

Instantiate plugin
Double-click to open Editor.
Click “Open Window 2” button to open second window.
Delete using right-click popup menu (with second window still open).
[CRASH]

The debug log shows “objc[89154]: Attempt to use unknown class 0x600000c45ef0.”

It should be noted that just running the compiled 5.4.7 AudioPluginHost and doing the same things does not crash on delete.

Here are a few reference shots:

Screen Shot 2020-07-16 at 11.36.24 AM

Sounds like your second window is not being destroyed when the editor’s destructor is called. This could lead to messages being passed to a non-existent listener. Seeing your code for creating the window and for destroying it would help, probably. My guess is you aren’t keeping a pointer to that second window and deleting it when the editor closes, (or else you’re not disconnecting a listener of some sort before destroying the component that’s listening).

Thanks, but I believe I am doing everything correctly. I will put the code here, but the project can be downloaded above. It does not crash with the VST2 version, or the AU version, or on Windows. It only crashes with the VST3 version on Mac OSX, with JUCE 6 (and not JUCE 5).

/*
  ==============================================================================

    This file contains the basic framework code for a JUCE plugin editor.

  ==============================================================================
*/

#pragma once

#include <JuceHeader.h>
#include "PluginProcessor.h"
class PluginWithWindowAudioProcessorEditor;

using namespace juce;

//==============================================================================
/**
*/

class Window2Component    : public Component
{
public:
    Window2Component(PluginWithWindowAudioProcessorEditor& mainRef);
    
    void paint(Graphics& g) override;
    void resized() override;
    
private:
    PluginWithWindowAudioProcessorEditor& mainComponent;
    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Window2Component)
};

class Window2   : public DocumentWindow
{
public:
    Window2(PluginWithWindowAudioProcessorEditor& mainRef, Window2Component *c, const String& name, Colour backgroundColour, int buttonsNeeded);
    
    void closeButtonPressed() override;
    
    PluginWithWindowAudioProcessorEditor& getMainComponent() { return mainComponent; };
private:
    PluginWithWindowAudioProcessorEditor& mainComponent;
    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Window2)
};

//==============================================================================

class PluginWithWindowAudioProcessorEditor  : public AudioProcessorEditor
{
public:
    PluginWithWindowAudioProcessorEditor (PluginWithWindowAudioProcessor&);
    ~PluginWithWindowAudioProcessorEditor() override;

    //==============================================================================
    void paint (Graphics&) override;
    void resized() override;

    void closeWindow2();
    void openWindow2();

private:
    TextButton openWindow2Button   { "Open Window 2" };
    std::unique_ptr<Window2> window2;

    // This reference is provided as a quick way for your editor to
    // access the processor object that created it.
    PluginWithWindowAudioProcessor& audioProcessor;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginWithWindowAudioProcessorEditor)
};

/*
  ==============================================================================

    This file contains the basic framework code for a JUCE plugin editor.

  ==============================================================================
*/

#include "PluginProcessor.h"
#include "PluginEditor.h"

//==============================================================================
PluginWithWindowAudioProcessorEditor::PluginWithWindowAudioProcessorEditor (PluginWithWindowAudioProcessor& p)
    : AudioProcessorEditor (&p), audioProcessor (p)
{
    addAndMakeVisible(openWindow2Button);
    openWindow2Button.onClick = [this] { openWindow2(); };

    // Make sure that before the constructor has finished, you've set the
    // editor's size to whatever you need it to be.
    setSize (400, 300);
}

PluginWithWindowAudioProcessorEditor::~PluginWithWindowAudioProcessorEditor()
{
}

//==============================================================================
void PluginWithWindowAudioProcessorEditor::paint (juce::Graphics& g)
{
    // (Our component is opaque, so we must completely fill the background with a solid colour)
    g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));

    g.setColour (juce::Colours::white);
    g.setFont (15.0f);
    g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1);
}

void PluginWithWindowAudioProcessorEditor::resized()
{
    // This is generally where you'll want to lay out the positions of any
    // subcomponents in your editor..
    openWindow2Button.setBounds(getLocalBounds().reduced(20).removeFromTop(40));
}

void PluginWithWindowAudioProcessorEditor::openWindow2()
{
    if (!window2)
    {
        window2.reset(new Window2(*this,
                                  new Window2Component(*this),
                                  "Window 2",
                                  Desktop::getInstance().getDefaultLookAndFeel().
                                  findColour(ResizableWindow::backgroundColourId),
                                  DocumentWindow::allButtons));
    }
    window2->setVisible(true);
}


void PluginWithWindowAudioProcessorEditor::closeWindow2()
{
    window2.reset(nullptr);
}

//==============================================================================

Window2Component::Window2Component(PluginWithWindowAudioProcessorEditor& mainRef)
: mainComponent(mainRef)
{
    setSize(300, 400);
}

void Window2Component::paint(Graphics& g)
{
    g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));   // clear the background
}

void Window2Component::resized()
{
}

Window2::Window2(PluginWithWindowAudioProcessorEditor& mainRef, Window2Component *c, const String& name, Colour backgroundColour, int buttonsNeeded)
: DocumentWindow(name, backgroundColour, buttonsNeeded)
, mainComponent(mainRef)
{
    setResizable(true, false);
    setUsingNativeTitleBar(true);
    
    // Let the child determine the size, and just define top-left window position here
    setContentOwned(c, true);
    setTopLeftPosition(100, 100);
}

void Window2::closeButtonPressed()
{
    mainComponent.closeWindow2();
}

If you’re truly creating a separate “window”, then you can’t leave those open when closing a plugin. Some VST3 hosts (like Cubase) crash if a window is left open, even if it’s just a popup menu. All open windows need to be explicitly closed when the editor’s destructor is executed.

I have tried specifically closing the second window, and setting it’s pointer to nullptr in the Editor’s destructor, as well, and it has no effect and the VST3 still crashes in JUCE 6 (mac, but not windows):


header:
    std::unique_ptr<Window2> window2;

...

PluginWithWindowAudioProcessorEditor::~PluginWithWindowAudioProcessorEditor()
{
    closeWindow2();
    window2 = nullptr;
}

It crashes in [NSApp run] which is part of the Mac AppKit or whatever, I guess?

Might be unrelated, but I was told that OSX 10.15 SDK is broken for hosting, and that even Logic links to OSX SDK 10.13.
The problem sounds related to the leak error I was experiencing, so it might be worth a try, I didn’t find the time to test myself yet,

Daniel, thanks for trying to help. I am building on Mojave, Xcode 10.3, and as far as I can tell, am linking to the 10.11 SDK. That would be the “Deployment Target”, right?

Screen-Shot-2020-07-21-at-8.11.29-AM

This is an issue in the VST3 hosting in JUCE that was introduced in 814f317. The reason for adding the call to CFBundleUnloadExecutable() was to fix an issue with loading instances of some plug-ins (Retrologue and Padshop I’ve seen so far) a second time after removing them, but it can cause problems due to not shutting down the Obj-C runtime correctly which is the cause of the crash you are seeing when you delete the plug-in instance with a second window open. We’re looking in to a long term solution for this which will fix both issues.

It’s worth noting that opening another window from your plug-in isn’t advisable - it can cause issues with some hosts and is also bad UX design as users can have many instances of your plug-in loaded in a single session so opening arbitrary windows from each of them is not good. Keep everything in a single window with overlays, pop-ups etc.

3 Likes

Thanks ed95, will look forward to the fix and not worry about it anymore.

My usage for this was a couple of debug windows that would not be present in a release version, so I’m totally in agreement here. I was just worried when the VST3 started crashing in JUCE 6 and not JUCE 5. Thanks for looking into it.

As long the window is closed, before the editor is deleted, i don’t know any host where this is currently a problem. Also restricting popups menus to the editor area is somehow clunky. Especially when the editor area is not very big.

Sometimes this isn’t an option because a plug-in may have a strongly vertical form factor (imagine a channel strip) in which it’s hard to fit messages to the user that are by their nature very horizontal.

Or plug-ins that resemble racks which are very horizontal, displaying a popup menu easily exceeds their vertical size

The main problem with additional windows is IMHO that they never stay above the DAW windows, except they are AlwaysOnTop, wich ist a PITA in itself…
But that is up to the UX designer

1 Like

Any chance this has received further attention? Thanks…

This has been fixed on the develop branch:

You’ll need to rebuild the AudioPluginHost.

1 Like

Thanks, Ed.