EXC_BAD_ACCESS with SliderAttachment (overflow?)

Hey every one!

I am just trying to connect a custom Slider to the AudioProcessor, but I am receiving these errors:


These errors only happen when I add the private member
AudioProcessorValueTreeState::SliderAttachment gainAttachment;

and add it to the initialization list with
gainAttachment(owner.state, "gain", gainSlider),

Any ideas? Thank you!

Code

#pragma once

//==============================================================================
class GainerProcessor  : public AudioProcessor
{
public: //0

    //==============================================================================
    GainerProcessor()
        : AudioProcessor (BusesProperties().withInput  ("Input",  AudioChannelSet::stereo())
                                           .withOutput ("Output", AudioChannelSet::stereo())),
    state (*this,
           nullptr,
           "state",
           {
               std::make_unique<AudioParameterFloat> (
                                                      "blah",
                                                      "Gain",
                                                      NormalisableRange<float> (0.0f, 11.0f),
                                                      0.9f
                                                   )
           })
    {
    }

    ~GainerProcessor() {}
    
    // Members
    AudioProcessorValueTreeState state;

    //==============================================================================
    void prepareToPlay (double, int) override {}
    void releaseResources() override {}
    void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override
    {
        jassert (! isUsingDoublePrecision());
        auto gainParamValue = state.getParameter("gain") -> getValue();
        buffer.applyGain(gainParamValue);
    }
    void processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages) override
    {
        jassert (isUsingDoublePrecision());
        auto gainParamValue = state.getParameter("gain") -> getValue();
        buffer.applyGain(gainParamValue);
    }
    //==============================================================================
    AudioProcessorEditor* createEditor() override          {
        return new GainerEditor (*this); }
    bool hasEditor() const override                        { return true;   }

    //==============================================================================
    const String getName() const override                  { return "Gain PlugIn"; }
    bool acceptsMidi() const override                      { return false; }
    bool producesMidi() const override                     { return false; }
    double getTailLengthSeconds() const override           { return 0; }

    //==============================================================================
    int getNumPrograms() override                          { return 1; }
    int getCurrentProgram() override                       { return 0; }
    void setCurrentProgram (int) override                  {}
    const String getProgramName (int) override             { return {}; }
    void changeProgramName (int, const String&) override   {}

    //==============================================================================
    void getStateInformation (MemoryBlock& destData) override
    {
    }

    void setStateInformation (const void* data, int sizeInBytes) override
    {
    }

    //==============================================================================
    bool isBusesLayoutSupported (const BusesLayout& layouts) const override
    {
        const auto& mainInLayout  = layouts.getChannelSet (true,  0);
        const auto& mainOutLayout = layouts.getChannelSet (false, 0);
        return (mainInLayout == mainOutLayout && (! mainInLayout.isDisabled()));
    }

private: //0
    
    //======================================================================
    //======================= Start Inner GainerEditor =====================
    //======================================================================
    
    class GainerEditor : public AudioProcessorEditor,
                         private Value::Listener
    {
    public: //1
        GainerEditor (GainerProcessor& owner) : AudioProcessorEditor (owner),
                                                gainAttachment(owner.state, "blah",  gainSlider)
        {
            // Set editor properties
            setSize(700, 500);
            
            // Set knob properties
            gainSlider.setBounds(250, 150, 200, 200);
            gainSlider.setSliderStyle(Slider::SliderStyle::Rotary);
            gainSlider.setTextBoxStyle(Slider::TextBoxBelow, true, 100, 25);
            gainSlider.setDoubleClickReturnValue(true, 0.00, ModifierKeys());
            addAndMakeVisible (gainSlider);
        }
        ~GainerEditor() {}
        void paint (Graphics& g) override
        {
            // Style component
            g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
            g.setColour (Colours::white);
        }
        
    private: //1
        
        AudioProcessorValueTreeState::SliderAttachment gainAttachment;
        Slider gainSlider;
        
        // Internal
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GainerEditor)
        void valueChanged (Value&) override
        {
            //        setSize (lastUIWidth.getValue(), lastUIHeight.getValue());
        }
    };
    //======================================================================
    //======================= End Inner GainerEditor =======================
    //======================================================================
    //======================================================================
    
//    AudioParameterFloat* gain;

    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GainerProcessor)
};

The slider and the slider attachment are declared (and thus created) in the wrong order. Put the gainSlider before the gainAttachment in the editor class declarations.

2 Likes

Genius! Thank you so much, it worked.

I am new to this forum, do I mark this post as complete? Or can I mark your answer as correct? Or should I change the title to [ANSWERED] ?

Xenakios is totally right and obviously it helped, however I think you should learn to help yourself, so a few additional explanations might help you to understand what went wrong:

  • EXC_BAD_ACCESS always means that you are trying to use some object or memory region that does not exist, therefore the application will be aborted if not run under a debugger
  • You run into this error because the members of a class are deleted in a reverse order to their construction. You declared the Slider below your SliderAttachment, so when your editor gets deleted there is a short period of time where the Slider has already been deleted while the Attachment is still active. If it tries to access the slider it referred to in exactly that moment it tries to access an object that no longer exists
  • Other common situations that trigger such an errors are when you try to access an array field that is out of the range of the array or if you are trying to dereference a nullptr
  • An overflow – as you assumed in the topic – is something completely different, it will occur if you trying to increase the value of a numerical variable beyond the limit of the value that can be represented by the variable’s precision in bits. This will lead to a drastic, unexpected varibable value changes, however your program won’t neccesarrily crash because of an overflow, it might continue working with wrong values. However those wrong values might lead to unexpected behavior wich might also crash the program…
2 Likes

I’m taking your help as well. Thank you :slight_smile: