buttonStateChanged - Exception Unhandled

I am trying to track down a bug in my synthesizer happening in my PluginEditor, when I hit a button to create a random wavetable waveform. If just compile in “debug” mode, a crash of the plugin happens occasionally, and I searched over and over again in the waveform producing code and never found a problem. If I run the compiler in debugging mode, I may be able to click the button a few times, waiting each time until waveform has been created, which only takes milliseconds, before I get the following exception thrown in juce_Button.cpp;

void Button::sendStateMessage()
{
    Component::BailOutChecker checker (this);

    buttonStateChanged();

    if (checker.shouldBailOut())
        return;

    // The exception is thrown on the below code line
    //  Unhandled exception thrown: read access violation.
    // l.**** was 0xFFFFFFFFFFFFFFEF.
    buttonListeners.callChecked (checker, [this] (Listener& l) { l.buttonStateChanged (this); });

    if (checker.shouldBailOut())
        return;

    if (onStateChange != nullptr)
        onStateChange();
}

I am at a total loss to what could be causing this problem, so if anyone have any idea, I’d appreciate very much any feedback, thanks.

What other objects have you added as listeners to this Button? Is it possible one of them no longer exists at the time you are clicking on the Button?

Thanks for offering help. I have only one listerner on this button, and for that matter all my other other buttons and sliders.

Although I have over 100 buttons and several hundreds knobs, which all seemingly (this button is the only I have tried debugging mode on) works fine, spread out over 20 or so components, none are “listened” to individually, as all are only “listened” to in PluginEditor, where I process change on every single button and slider.

Your reply made me rethink about the problem. As I myself explained I have over 100 buttons and several hundreds knobs, all configured and processed in a similar fashion. So that one button would not process right was just not very likely. So I started commenting out sections of my “Random Waveform Generator” and put in a test loop of 100 to try and find errors in my code, which I was now convinced there was. And lo and behold, in two different areas I found and fixed code that occasionally caused an array to be accessed out of bounds.

So thank you very much for actually convincing me to think that the problem was in my algorithm, and not the button. And apparently the array out of bound access caused the weird “button exception”.

Glad my question was helpful. From the unhandled exception error text you put in your first post, I first guessed that one of the button Listeners (which are stored as an array of pointers) had been deleted… although looking closer at that JUCE code now, I see it’s doing its own check (with shouldBailOut()) for that scenario. So my guess was wrong, but it got you rethinking at least!

Is your “Random Waveform Generator” part of the Editor, or the Processor? Does it run directly in response to a button click (i.e. does it run on the message thread), or does it defer running (via setting a flag, or using some other kind of async message) so that it gets run later on the audio thread?

I think @refusesoftware is right that the original issue is a deleted listener that hasn’t been removed from the listener list. I don’t think an out-of-bounds array access should cause the error you described.

Assuming this is the case, you’ll need to add a removeListener() call before your listener is deleted (usually in its destructor, but that depends on how you’ve implemented things).

Btw, the shouldBailOut() checks in sendStateMessage() are checking for the button being deleted, not any of its listeners, so they do not protect against this.

OK, I kind of skimmed over the JUCE code and missed that detail. The shouldBailOut() docs say:

Returns true if either of the two components have been deleted since this object was created.

Which I read fast and assumed that meant the Component OR its Listener. I’m not actually sure what “either of the two components” means, actually…

I’m not sure which two components it’s referring to, either! The class holds a weak reference to the component you provide in the constructor, and shouldBailOut() simply checks to see if that reference is a nullptr or not:

bool Component::BailOutChecker::shouldBailOut() const noexcept
{
    return safePointer == nullptr;
}

To make things even less clear, the constructor documentation says (emphasis mine):

Creates a checker that watches one component.

My “Random Waveform Generator” is part of my PluginEditor, and only run there. It is part of an elaborate “Waveform Generator” algorithm, where I can edit or create literally millions of different waveforms via about 60 sliders, knobs, and buttons. Each can be adjusted manually, or I can use a random function which sets the sliders, knobs, and buttons, either way it then proceeds to create the waveform to a temporary wavetable array, and then when synthVoice is not using that, it is transfers the wavetable the “active” array. And yes the algorithm runs immediately when hitting the “Random” button.

To repeat I only have one(1) listener on ALL my sliders and buttons. A, again one (1), listener is added once to all my sliders and knobs, no matter what component they are part of, when PluginEditor is opened as they are all dealt with, user interaction processed there, and I NEVER delete any!

The number of listeners is not important. If you have one listener, and it is deleted (or goes out of scope) before the button that it is registered with, you will encounter the exception you described when the button’s state changes. Maybe you’ve got something else going on, but on more than one occassion I’ve experienced the exact same exception in the exact same location and a missing removeListener() call was to blame.