Strangest bug I've seen!


#1

I think I’ve come across one of the strangest bugs I have ever seen, any ideas whats going on? It appeared while starting some long overdue code refactoring. I have created a class A which extends a class of mine, B. A is an AudioIODeviceCallback. A has a member of class, D which is an AudioIODeviceCallback. B has a member another class E which is an AudioIODevice callback.

So! When creating A, I register 3 objects with the AudioDeviceManager to receive callbacks (A,D and E). D is a Live input waveform display, like in the JUCE record demo. For some reason, when A is registered with the AudioDeviceManager, the waveform display (D) will work properly, but if I try to change the channel it is displaying (via a drop-down in the gui) it will not change from whatever the first channel set was to display. If I do not add A to AudioDeviceManager, it works fine and whichever channel I select in the gui displays. By chance testing some other stuff out, I added a member const float* someName and its mere presence makes it work fine (with A registered with the AudioDeviceManager)…

What the!?

EDIT With that weird fix (adding a const float* as a member of the class, even though I dont do anything with it) the program destructs and quits fine, although without it, the program stalls when quitting and I get an error with the destruction of class D (waveform display ScopedPointer-- EXC_BAD_ACCESS). Not sure how adding that can fix the display problem with the waveform class and this problem upon destruction?


#2

It sounds like the compiler may by aligning your outer and inner objects so that they share the same memory address… So when you register those two objects as callbacks, you’re actually passing the same pointer twice, and the device will ignore the second one, thinking it already has that callback registered…

Search for the “empty base class optimisation” for more info, but in this case I’m surprised that it’d happen because your objects have virtual functions… There are some strict parts of the C++ standard that try to make sure that objects all have unique addresses, but it’s a complicated area.


#3

Interesting… It seems like something like that is going on, and perhaps adding that float* [] is pushing a memory address back or something and fixing it? Do you have any idea what the best thing to do is in a situation like this? Seems a bit superfluous to just have that array in there for no reason…


#4

You could just store your inner object with a ScopedPointer rather than using composition. Or like I said, read about the empty base class optimisation - although it’s a pretty obscure c++ principal, it’s part of the standard so you can expect all compilers to follow it.


#5

Hmm, just to make sure were on the same page, I may have been a bit confusing in my initial explanation-- I’m not doing any nested class declarations, and none of the classes are actually empty. The base class Recorder has various variables and objects in it. It has one virtual method which is implemented by its inheritor, a class called AudioRecorder. AudioRecorder has other variables and objects, and creates an instance (scopedptr) of the live audio display component, which I treat it like any other normal component. This is the component exhibiting the strange behavior…So I’m not sure EBCO applies, sorry if I was a bit confusing. Of course its possible Im missing something about ebco :?


#6

Upon a bit more restructuring today (moving the actual float*[] into the Recorder base class and accessing via setters/getters since it is common to all classes which inherit Recorder), the problem disappeared, and things are hunky dory. Still a little bit of a mystery, and was a pain to figure out the culprit, but happy to have learned around ebco and all that :slight_smile: Thanks Jules