Assert when releasing plugin code


#1

I’m constantly getting this (i didn’t tested the VstWrapper from some time) every time i close the plugin compiled in debug mode (or i close the host):

Debugging the code a little bit, it seems that somehow comparing the pointers in the Array<void*> activePlugins with the juce wrapper fails somehow, cause i can see my plugin inside the array correctly.


#2

That should be impossible… If you step into the Array::contains method, does it look like the pointer that’s being passed-in is different to the one that’s already stored in the array?


#3

Please follow the full story here.

Debugged the host with my plugin loaded. Assertion fired as soon as the audio thread is up and running:

JUCE Assertion failure in ../libraries/juce/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp, line 553

Program received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0xb7bc86d0 (LWP 26388)]
0xffffe424 in __kernel_vsyscall ()

Switched to the right thread:

(gdb) thread 4
[Switching to thread 4 (Thread 0xb5b0fb70 (LWP 26393))]#0  0xffffe424 in __kernel_vsyscall ()

(gdb) bt
#0  0xffffe424 in __kernel_vsyscall ()
#1  0xb7c1b026 in kill () from /lib/libc.so.6
#2  0xb25bcc09 in JuceVSTWrapper::processReplacing (this=0xa081858, inputs=0x9fa0020, outputs=0x9fa0220, numSamples=1024)
    at ../libraries/juce/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp:553
#3  0xb25b9fe6 in AudioEffect::processClassReplacing (e=0xa081878, inputs=0x9fa0020, outputs=0x9fa0220, sampleFrames=1024)
    at ../libraries/vstsdk2.4/public.sdk/source/vst2.x/audioeffect.cpp:60
#4  0x080e1e3e in CVST::subProcess(int, int) ()
#5  0x080e2473 in CVST::process(int) ()
#6  0x080917d8 in processComp(CAudioCable*, int, CPDC*) ()
#7  0x08091b7f in CXT::subProcess(int, int) ()
#8  0x08094199 in CXT::process(int) ()
#9  0x0817df5f in libio(float**, float**, long, long, long, void*, int) ()
#10 0xb7fd3b6f in CALSAAudioThread::execute() () from /home/kraken/Apps/energyXT/libaam.so
#11 0xb7fd152c in threadFunc(void*) () from /home/kraken/Apps/energyXT/libaam.so
#12 0xb7fa6e83 in start_thread () from /lib/libpthread.so.0
#13 0xb7cbeeee in clone () from /lib/libc.so.6

Navigate up 2 frames:

(gdb) up
#1  0xb7c1b026 in kill () from /lib/libc.so.6

(gdb) up
#2  0xb25bcc09 in JuceVSTWrapper::processReplacing (this=0xa081858, inputs=0x9fa0020, outputs=0x9fa0220, numSamples=1024)
    at ../libraries/juce/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp:553
553	        jassert (activePlugins.contains (this));

Printed this and the first and only element in the array:

(gdb) print this
$1 = (JuceVSTWrapper *) 0xa081858

(gdb) print activePlugins.data.elements.data[0]
$2 = (void *) 0xa081858

How do you explain this ?

Probably the contains function of the Array got messed up comparing void pointers ? it seems so strange !


#4

Well, that seems mad, but it could actually be correct - if the plugin was added to the array and then removed, the first element in the array would still contain the pointer, but the array’s size would be 0.

Could it be possible that the processReplacing() method is being called just after the plugin has been deleted…? If I was debugging this, I think my next move would be to add some logging at each place where the activePlugins array is used, so you can see the order in which things are being added and removed from it.


#5

After a bit of discovering i can see that at that point in the Array numAllocated == 1 but numUsed == 0, so actually the compare is not taking place.


#6

[quote=“jules”]Well, that seems mad, but it could actually be correct - if the plugin was added to the array and then removed, the first element in the array would still contain the pointer, but the array’s size would be 0.

Could it be possible that the processReplacing() method is being called just after the plugin has been deleted…? If I was debugging this, I think my next move would be to add some logging at each place where the activePlugins array is used, so you can see the order in which things are being added and removed from it.[/quote]

it’s strange, cause i reach this problem right after loading the plugin in a track, and i don’t reach logs in wrong order. so everything is ok: constructor, process, destructor. It is possible that something is corrupting the static Array ?


#7

It’s incredibly unlikely… The only way I think that could happen would be if there was a race condition between multiple threads which were trying to create/delete plugins at the same time? If you think that’s possible, a quick test would be to make the array thread-safe like this:

…and see if that makes any difference.


#8

[quote=“jules”]It’s incredibly unlikely… The only way I think that could happen would be if there was a race condition between multiple threads which were trying to create/delete plugins at the same time? If you think that’s possible, a quick test would be to make the array thread-safe like this:

…and see if that makes any difference.[/quote]

I tried but this makes no difference at all. i also put a watch to activePlugins.numUsed and stepped into Array.add, but it seems that this:

is not incrementing numUsed (is zero before and after the call) ! Geez, this is the most obscure bug i’ve ever encounter… I don’t know if it’s worth investigating or completely shut up the asserts (but going to be hit by something more heavy later on).


#9

Wow. If that’s genuinely what’s happening, then it must be a compiler bug… What happens if you re-write as two instructions?:

new (data.elements + numUsed) ElementType (newElement); ++numUsed;


#10

I’ve slightly changed the function to:

    void add (ParameterType newElement)
    {
        const ScopedLockType lock (getLock());
        data.ensureAllocatedSize (numUsed + 1);
        new (data.elements + numUsed) ElementType (newElement);
        ++numUsed;
    }

and now numUsed is correctly set to 1, and i’m not getting anymore the assert. maybe it’s a gcc bug ?

here it is:

and here are the options used to compile my sources:

EDIT: you beat me to it !


#11

mmmh, i’ve speak too early. i’m still getting the asserts.

probably there are others of these to cure ?

btw here it is what shocks me:

(gdb) next
344	        activePlugins.add (this);
(gdb) step
juce::Array<void*, juce::CriticalSection>::add (this=0xb33f95e0, newElement=0xa084ca0)
    at ../sources/juce/../../libraries/juce/amalgamation/../src/core/../io/files/../../containers/juce_Array.h:347
347	        const ScopedLockType lock (getLock());
(gdb) next
348	        data.ensureAllocatedSize (numUsed + 1);
(gdb) next
349	        new (data.elements + numUsed) ElementType (newElement);
(gdb) print activePlugins.numUsed
$1 = 0
(gdb) next
350	        ++numUsed;
(gdb) print activePlugins.numUsed
$2 = 0

? i’m really disappointed !


#12

I suspect what you’re seeing is just because the binary is optimised too heavily for the debugger to be able to get the values correctly. If that method didn’t work correctly, very little of the library would work at all. A better test might be to make it print some logging messages with the value, so you can see the real number.


#13

i should try this, but obviously if i’m hitting the asserts, then printing that variable should again be zero ? just guessing…

anyway i’m not compiling with any optimization:

-O0 or no -O option (default)
    At this optimization level GCC does not perform any optimization and compiles the source code in the most straightforward way possible. Each command in the source code is converted directly to the corresponding instructions in the executable file, without rearrangement. This is the best option to use when debugging a program and is the default if no optimization level option is specified. 

#14

Hmm, it’s all very confusing, I’m really not sure what to suggest! A compiler error seems unlikely, or else arrays wouldn’t work at all. Maybe try inserting a bit of code to do a test, e.g.

Array a;
a.add (123);
jassert (a.contains (123));
a.removeValue (123);
jassert (! a.contains (123));


#15

No problems if i do it like this somewhere in the code, and even declaring the array as global static, and splitting the asserts in constructor/destructor of the plugin… i’ve no clue !!! this is the first time i don’t trust what i see in lot of years of C++ coding !


#16

despites the assert hits (which i got commented out), when i’m using multiple instances of the plugin i’m seeing this is correctly called in ~JuceVSTWrapper after the last plugin got deallocated:

        if (activePlugins.size() == 0)

so i’m starting to doubt the assert hit is a false positive ?


#17

It does sound like a false positive, but I’m stuck for ideas about why or how it could happen! Keep me posted if you notice any other clues!