Lambda missing 'this' on Windows but works on Linux [SOLVED]

I’m having an issue, where a lambda function call fails on windows, while perfectly working on linux. It only fails if I try to access any class member, which makes me assume that somehow the ‘this’ pointer is not captured or changes somehow:
This works:

Voice() {
    env[0].onEnvelopeEnd = [&]() { 
        std::cout << "foo\n";
    };
}

this doesn’t:

Voice() {
    env[0].onEnvelopeEnd = [&]() { 
        onEnvelopeEnd();
    };
}

The debugger goes into some system library, where there’s a throw. Any ideas?

Are you sure the voice you are referencing still exists at the time the lambda is called?

1 Like

Maybe try capturing “this” explicitly instead of relying on capturing “&”? Also, if the Voice class is used as a value somewhere, the captured “this” pointer can easily become invalid because value instances of objects may get destroyed and copied.

1 Like

Yes, the voices have the same lifetime as the audioprocessor

DIdn’t help either.

I found a super awkward solution by capturing a pointer to the variable I want to change by value and then accessing it.

However, after this problem was solved another one appeared, where every parameter update from the GUI throws another exception. From the debugger it seems it is about lambdas again, but this time inside the JUCE messaging system and therefore out of my reach.

This makes me wonder if I missed some compile options or if I’m doing anything else wrong? I’m rather unfamiliar with Windows/VisualStudio so I just used the “out of the box” project JUCE generated.

Maybe you could try debug outputting the “this” and “env[0]” pointers when inside the lambda and when constructing the Voice object? You could see if the pointers are changing, which could indicate if there’s some kind of destruction/copy construction etc thing going on.

Yep, it does indeed change… Could you shed some more light on what might cause this? The array of voices is a member of the AudioProcessor and I don’t recreate it or anything…

What exactly is meant by “used as a value” here?

Maybe deleting the copy constructors and seeing where it fails might help?

What kind of array are the voices in? Are the voices stored in the array as values or indirectly via pointers? Do you add the voices using some kind of “add” or “push_back” feature of the array?

No just a very basic C++ array á la

//VOICES is defined as 12
Voice m_voice[VOICES];

after some further research, I think the problem lies much much deeper. I can quite literally capture a variable by value into a lambda with values 0 through 11 and print them. Then when the lambda is called, its values are above 30.

Same with lambdas in the JUCE messenger system which I didn’t even touch. I get weird errors there, sometimes segfaults, everything behaving so weirdly.

For now development has come to a complete halt for me, I’m superconfused and don’t know what’s going on…

I would suspect some kind of stack or heap corruption that for some reason manifests on Windows but not Linux.

Maybe a shot in the dark, but have you tried re-exporting the Visual Studio solution and completely rebuilding from scratch? That has sometimes helped with some really obscure crashes and such. What version of Visual Studio are you using?

I just tried, didn’t help. The version I’m using is Express2017. There’s a 2019 release now if I’m not mistaken?

I also have access to a macbook at work, will try to get it running there. Maybe I’ll get some more insights.

If you have a recent enough version of XCode, you can use Address Sanitizer and Undefined Behavior Sanitizer pretty easily to find memory corruption issues. (Also I guess you could try Valgrind on Linux…)

Regarding Visual Studio and lambdas and capturing “this”, my code is full of those and there have mostly been no issues. Usually the problem has been that the “this” pointer captured by a lambda somehow got invalid because the “this” object was deleted before the lambda code was executed.

Did you try deleting the copy constructor and copy assignment of your Voice class to see if the compiler for some reason is attempting to generate code that uses those?

From what I could tell it ran well on Mac, but I didn’t have too much time to fiddle around with it.

Maybe I will try going back in my commit history and search for a point where it is still working, to hopefully indentify the problem in the process.

Are you doing any manual memory management? I once saw this kind of thing happen on windows with an errant call to delete when I needed to use delete[].

The only dynamical memory allocation/deletion in my entire code base are the GUIControlAttachements, these are wrapped in unique pointers though.

Wait a second… my entire wavetables are created dynamically. However, I don’t ever call delete before the program closes, so this doesn’t apply? I’ll investigate, thanks for your input!

Ok I kept working on other stuff on linux. When I retried on Windows it was mostly working, but still strange behaviour:

The one that persisted from before is that it will hit an assertion 3 times on startup telling me I have duplicate controls, and I quadruple checked, I don’t. The new weird bug on the blog is:
On closing the app it hits some assertion with the accompanying text:

// This will fail if you've called beginChangeGesture() without having made
// a corresponding call to endChangeGesture...

and I most certainly did not call this function.
So like stated before the problem is probably some kind of memory corruption (and then undefined behaviour). I will dedicate some time the next days diving into this.

I don’t think you guys can help me any further at this point (I’m happy to be proven otherwise tho).
Anyway thanks for everybodys help! :slight_smile:

SliderAttachment call this when controls start dragging, if you’re using that attachment class

1 Like

After all this time I found the error by accident. The envelope was a member of “Voice” and layed in memory directly after CombFilter m_comb_filter[2]. I accidentally messed up a for-loop, where I accessed m_comb_filter[2] and set something on it, which in turn messed up the envelope.

I really don’t know why you should care about this, but I just had a moment of enlightenment :smiley: