Extremely strange LeakedObjectDetector behavior


#1

This is somewhat of a continuation of another thread where I was asking about using LeakedObjectDetector in base classes. I am continuing to struggle with a certain base class throwing spurious LeakedObjectDetector assertions. Here is a sample of the output when I add DBG statements to the constructor and destructor:

ValueTreeObject Edit CONSTRUCT
ValueTreeObject MasterTrack CONSTRUCT
ValueTreeObject Tempo CONSTRUCT
ValueTreeObject TimeSignature CONSTRUCT
ValueTreeObject KeySignature CONSTRUCT
ValueTreeObject Transport CONSTRUCT
ValueTreeObject ArrangementViewModel CONSTRUCT
ValueTreeObject TrackList CONSTRUCT
ValueTreeObject TrackList DELETE
ValueTreeObject ArrangementViewModel DELETE
ValueTreeObject Transport DELETE
*** Dangling pointer deletion! Class: ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:64
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
ValueTreeObject KeySignature DELETE
*** Dangling pointer deletion! Class: ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:64
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
ValueTreeObject TimeSignature DELETE
*** Dangling pointer deletion! Class: ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:64
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
ValueTreeObject Tempo DELETE
*** Dangling pointer deletion! Class: ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:64
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
ValueTreeObject MasterTrack DELETE
*** Dangling pointer deletion! Class: ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:64
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
ValueTreeObject Edit DELETE
*** Leaked objects detected: 1 instance(s) of class ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:88
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
*** Leaked objects detected: 1 instance(s) of class ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:88
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
*** Leaked objects detected: 1 instance(s) of class ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:88
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
*** Leaked objects detected: 1 instance(s) of class ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:88
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
*** Leaked objects detected: 1 instance(s) of class ValueTreeObject
JUCE Assertion failure in juce_LeakedObjectDetector.h:88
Exception: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)

As you can see, 8 objects are constructed (on the stack, I might add) at launch time. On quit, 3 are deleted when going out of scope, then for the rest I get accused of deleting dangling pointers (again, this is all on the stack, so I know it’s BS) followed by being told those same pointers are being leaked immediately after.

This is the class in question:

I have been debugging this for weeks and I am at a loss. Removing the LeakedObjectDetector from the base class and using it in all the derived classes works as expected, but for whatever reason the base class completely breaks it.

My only guess at this point could have something to do with the fact that the class takes a const Identifier& as a template argument, where it refers to a globally-scoped object, but I don’t see how those could be related.


#2

That’s really odd that you get dangling pointer deletions. Have you tried running with address sanitiser?


#3

I know that you are very cautious with references and ownerships, but can you try to return the ValueTree object (sharing the internal object, no penalty) instead of a reference:

But that’s probably a red herring, since the expected problem would be the opposite, stuff deleted too early rather than being left over…


#4

(Reply to fabian, but also for @daniel)

Thanks a bunch for the suggestions! I tried running with the address sanitizer and it gave me an interesting result:

The particular call it seems to be complaining about is the getState() call, which it claims is not being made on a type of ValueTreeObject<&IDs::MasterTrack>… which is exactly what MasterTrack is derived from. Is there some special process to point a template parameter to a global variable? I have all the IDs I’m using defined here (based on @dave96’s code) , but perhaps I’m declaring them incorrectly:


#5

I may have figured it out - my IDs namespace (in hmnz_Identifiers.h) is full of const Identifier definitions which is included throughout several unrelated files. The problem is I overlooked the fact that these aren’t actually global objects, and they were getting defined multiple times local to certain translation units (?) when included in several different places.

As a result, when I assigned the template parameter to be a const Identifier&, the assigned references were sometimes different between definitions, causing the super confusing issues at runtime since the Identifiers were technically “equal” and appeared to work but were actually different definitions because they had template parameters referring to const Identifier objects which were technically stored in different places.

tl;dr pretty sure it’s because of multiple definitions of an lvalue template parameter causing discrepancies between compile-time and run-time objects.