Assertion failure on shutdown in juce_Singleton.h:72

Hi

I get the following assertion failure on shutdown, in a Project based on the Audio Plugin with Standalone App template in Projucer.

JUCE Assertion failure in juce_Singleton.h:72

The surrounding code looks like this:

                if (once)
                {
                    static bool createdOnceAlready = false;

                    if (createdOnceAlready)
                    {
                        // This means that the doNotRecreateAfterDeletion flag was set
                        // and you tried to create the singleton more than once.
                        jassertfalse;
                        return nullptr;
                    }

                    createdOnceAlready = true;
                }

Variables ‘once’ and ‘createdOnceAlready’ are both true.

The backtrace looks like this:

* thread #1, name = 'JUCE Message Thread', queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
  * frame #0: 0x000000010063c1f0 ClockMe`juce::SingletonHolder<juce::JuceMainMenuBarHolder, juce::DummyCriticalSection, true>::get(this=0x0000000100a4e198) at juce_Singleton.h:72:25
    frame #1: 0x000000010063c160 ClockMe`juce::JuceMainMenuBarHolder::getInstance() at juce_mac_MainMenu.mm:59:5
    frame #2: 0x000000010063be79 ClockMe`juce::JuceMainMenuHandler::getMainMenuBar() at juce_mac_MainMenu.mm:509:16
    frame #3: 0x00000001006372b7 ClockMe`juce::JuceMainMenuHandler::menuBarItemsChanged(this=0x0000600002123750, (null)=0x0000000000000000) at juce_mac_MainMenu.mm:173:25
    frame #4: 0x000000010059a450 ClockMe`juce::JuceMainMenuHandler::setMenu(this=0x0000600002123750, newMenuBarModel=0x0000000000000000, newExtraAppleMenuItems=0x0000000000000000, recentItemsName=0x00007ffeefbfd9b0) at juce_mac_MainMenu.mm:102:13
    frame #5: 0x000000010063bd04 ClockMe`juce::JuceMainMenuHandler::~JuceMainMenuHandler(this=0x0000600002123750) at juce_mac_MainMenu.mm:78:9
    frame #6: 0x00000001006371c5 ClockMe`juce::JuceMainMenuHandler::~JuceMainMenuHandler(this=0x0000600002123750) at juce_mac_MainMenu.mm:77:5
    frame #7: 0x00000001006371e9 ClockMe`juce::JuceMainMenuHandler::~JuceMainMenuHandler(this=0x0000600002123750) at juce_mac_MainMenu.mm:77:5
    frame #8: 0x0000000100385d70 ClockMe`juce::DeletedAtShutdown::deleteAll() at juce_DeletedAtShutdown.cpp:78:13
    frame #9: 0x0000000100385a9e ClockMe`juce::JUCEApplicationBase::appWillTerminateByForce() at juce_ApplicationBase.cpp:62:9
    frame #10: 0x000000010039e239 ClockMe`juce::AppDelegate::AppDelegateClass::applicationWillTerminate((null)=0x00006000000180b0, (null)="applicationWillTerminate:", (null)="NSApplicationWillTerminateNotification") at juce_mac_MessageManager.mm:170:13

So, we see that during destruction of JuceMainMenuHandler, the following line is called:
setMenu ( nullptr , nullptr , String());

This calls menuBarItemsChanged ( nullptr );, which again calls auto* menuBar = getMainMenuBar();, which calls JuceMainMenuBarHolder::getInstance()->mainMenuBar;

This main menu bar appears to have already been deleted and set to null. Clearly it is related to setting the main menu bar on mac.

My code for setting it is here:

class MainMenu : public MenuBarModel {
    MainComponent *mainComponent;
public:
    MainMenu( MainComponent *mainComponentUnowned ) : mainComponent( mainComponentUnowned ) {}
    
    virtual StringArray getMenuBarNames() {
        return StringArray( "File" );
    }
     
    virtual PopupMenu getMenuForIndex(int topLevelMenuIndex, const String &menuName) {
        PopupMenu result;
        result.addItem("Open", [this] { LoadFromFile(mainComponent); });
        result.addItem("Save", [this] { SaveToFile(mainComponent); });
        result.addItem("Export drums", [this] { ExportDrums(mainComponent); });
        return result;
    }
     
    virtual void menuItemSelected(int menuItemID, int topLevelMenuIndex) {}

};

void SetupMainMenu( MainComponent *mainComponent ) {
    static MainMenu mainMenu( mainComponent );
    MenuBarModel::setMacMainMenu( &mainMenu );
}

SetupMainMenu is called in the MainWindow constructor, which is located in Main.cpp and is mostly unchanged from the file autogenerated by Projucer. Is the error caused by me doing it wrong? In macOS, menus are provided in the main menu bar on top of the screen, and not attached to each window, so I try to keep it that way. Is this the correct way of doing that?

Unfortunately I stopped using the Projucer to maintain the project, because I needed to do things that the Projucer didn’t support, so it is now only maintained in Xcode. macOS version 10.14.6 (18G103), Xcode version 11.3.1 (11C504).

It would be better to make the MainMenu a member of the MainComponent instead of making it static.
I haven’t dug deep enough into that part of the code to say for sure that it solves your issues, but when I used the setMacMainMenu I didn’t have that singleton problem.

MainComponent::MainComponent()
{
    // ...
#if JUCE_MAC
    MenuBarModel::setMacMainMenu( &mainMenu );
#endif
}

MainComponent::~MainComponent()
{
#if JUCE_MAC
    MenuBarModel::setMacMainMenu( nullptr );
#endif
    // ...
}

// MainComponent member:
private:
    MainMenu mainMenu { this };

Good luck

1 Like

Thank you

After experimenting a bit, it turns out this is the line that fixed it:

MenuBarModel::setMacMainMenu( nullptr );

It seems the mac menu bar must be cleared during shutdown, before all the singletons are being destroyed.