SliderParameterAttachment halting at jassert on usage, although seems fine when opening GUI

I am setting up a SliderParameterAttachment with the following code:

	// Init slider
    // This fully constructs the slider and names it "unnamed" 
	controls.gain = make_shared<gui::GUI::Slider>();
         ...
	// Make attachment
	parameters.gainAttachment = (new
		juce::AudioProcessorValueTreeState::SliderAttachment(
			*stateParameters, "gain", *controls.gain->getSlider()));

I construct the Slider using this:

class Slider {
	shared_ptr<juce::Slider> slider = make_shared<juce::Slider>();
public:
	Slider() {
		slider->setName("unnamed");
	};

	shared_ptr<juce::Slider> getSlider();
};

Checking the following variable, slider, while I open the GUI results in the slider name value being the one I gave the SliderParameterAttachment, evident by the name I gave it (“unnamed”); so far, so good:

SliderParameterAttachment::SliderParameterAttachment (RangedAudioParameter& param,
                                                      Slider& s,
                                                      UndoManager* um)
    : slider (s),
...

Due to that, it seems to set up fine, but when I actually use the slider, suddenly a jassert halts the program, from here:

class Slider::Pimpl   : public AsyncUpdater, // this needs to be public otherwise it will cause an
                                             // error when JUCE_DLL_BUILD=1
                        private Value::Listener
{
...
    void setValue (double newValue, NotificationType notification)
    {
        // for a two-value style slider, you should use the setMinValue() and setMaxValue()
        // methods to set the two values.
        jassert (style != TwoValueHorizontal && style != TwoValueVertical);
...

I checked the Slider’s name at the halt, and it was NULL, unlike it was when I opened the GUI window, indicating that a different Slider was used for the SliderParameterAttachment.

I checked the Slider’s name one call before the error, at this code:

void Slider::setValue (double newValue, NotificationType notification)
{
    pimpl->setValue (newValue, notification);
}

The error at the jassert was:

Exception thrown: read access violation.
**this** was 0xFFFFFFFFFFFFFFD7.

I tried building it with Visual Studio’s Address Sanitizer option on, and it built fine, but I get a lot of linker errors from the usage of annotate_vector, something that’s a part of a different code base than the one I’m writing, although it also happens in my object files. Here are the linker errors that occur with Address Sanitizer:

...[everything builds fine]...
1>none2_SharedCode.vcxproj -> D:\Programming\Audio Tools\framework\none2\none2\Builds\VisualStudio2022\x64\Debug\Shared Code\none2.lib
2>------ Build started: Project: none2_VST3, Configuration: Debug x64 ------
2>none2.lib(include_juce_core.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_core.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_events.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_graphics.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_data_structures.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_gui_basics.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_audio_basics.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_audio_processors.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(PluginProcessor.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(include_juce_gui_extra.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(AudioData.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(None2App.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(ExampleApp.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(PluginEditor.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(Modulator.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>none2.lib(GUI.obj) : error LNK2038: mismatch detected for 'annotate_vector': value '1' doesn't match value '0' in include_juce_audio_plugin_client_VST3.obj
2>   Creating library D:\Programming\Audio Tools\framework\none2\none2\Builds\VisualStudio2022\x64\Debug\VST3\none2.lib and object D:\Programming\Audio Tools\framework\none2\none2\Builds\VisualStudio2022\x64\Debug\VST3\none2.exp
2>D:\Programming\Audio Tools\framework\none2\none2\Builds\VisualStudio2022\x64\Debug\VST3\\none2.vst3 : fatal error LNK1319: 15 mismatches detected
2>Done building project "none2_VST3.vcxproj" -- FAILED.
========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

What could cause this?

I noticed that after running the following (the class looks fine, no illegal references or illegal values, except that slider has a nullptr for pimpl):

void ParameterAttachment::handleAsyncUpdate()
{
    if (setValue != nullptr)
        setValue (parameter.convertFrom0to1 (lastValue));
}

The program goes through [External Code], and then runs the SliderParameterAttachment constructor all over again, but this time the input value for the Slider is a bad value.

Why would it need to create a new SliderParameterAttachment after calling the ParameterAttachment’s input setValue lambda?

I can’t see what happens in [External Code], so it’s difficult to tell.

The callstack, at that point, where there is then an illegitimate Slider object, looks like this:

 	none2.vst3!`juce::SliderParameterAttachment::SliderParameterAttachment'::`1'::<lambda_11_>::operator()(float f) Line 117	C++
 	[External Code]	
>	none2.vst3!juce::ParameterAttachment::handleAsyncUpdate() Line 110	C++

It is a bit hard to say from the code fragments.
We see the slider goes out of scope leading to the crash (since the console logs an Exception it is not the jassert that fails).

A possible explanation is destruction order: if the attachment is declared before the slider, the attachment will be destroyed when the slider is already gone, which leads to this crash. But it doesn’t completely add up with your description that it crashes when interacting.

I am weary of the shared_ptr, they sound like a swiss army knife, but in reality they can create such lifetime issues, that’s why I would recommend not to use them. There are a few cases where they are useful, but it’s better when you have a single point of ownership.