General Description
I have encountered a problem while debugging a Visual Studio project. This project has a large central class "MachineControl". It also stores the state it is currently in as a value of an enum class. While trying to fix an unrelated bug, I set up a few conditional breakpoints to solve it. After some confusing situations, I realized that the information I get from the debugger is wrong. The code runs on different values than are displayed by the debugger.
This value is wrong because when I step through the code, it actually behaves as if it is in the state StateEnum::Running(1).
IDE and Code Information
Wrong information found in everything related to the debugger:
- Displayed by Debugger mouseover
- Used in conditional breakpoints
- Autos
- Locals
- Watch
- "Immediate Window"
- Memory View
Correct Information:
- std::cout
- Code behavior
- Logging
Environment:
- Microsoft Visual Studio Professional 2019, 16.9.0
Code:
- Single-Threaded native code inside MachineControl class
- Managed C++ GUI project calling managed simulation wrapper DLL around native C++ static library (this explains the "managed to native" transition mentioned later)
Code Example
The wrong debug information occurs at a point that is hard to isolate. Sadly, I can't produce a minimal reproducible example. The following snippet is the most minimal illustrative code I have to show the general situation where the problem occurs:
class MachineControl : public EventReceiver <Evt>
{
StateEnum mState;
public:
void onEventReceived(const Evt& evt) override;
void processPeriodicTimer();
//...
};
void MachineControl::onEventReceived(const Evt& event) // called by other class through managed to native transition
{
switch (mState) // shows wrong information
{
case StateEnum::Running:
processRunning(event); // <-- code jumps here, even though mState is not shown to be in StateEnum::Running
break;
// handle other cases
}
//...
}
void MachineControl::processPeriodicTimer() // called from inside
{
switch (mState) // shows correct information
{
// ...
}
//...
}
// a thousand more lines of code before and after this
Observations
- StateEnum has values defined up to 18, but values higher than that show up in Debug info. The wrong displayed values don't follow any pattern I've recognized
- The MachineControl class contains many instances of "switch(mState)". Going through them all, the error seems to occur exactly when the Call Stack displays [Native to Managed Transition] below it, followed by [Managed to Native Transition], followed by some other class.
The above image illustrates a Call Stack when wrong debug information is shown.
Unsuccessful things I tried and/or verified
- Project runs in Debug configuration (mentioned in a similar StackOverflow post)
- Optimization disabled (/Od), mentioned in many articles I found online
- Using Flag /clr and not /clr:pure as mentioned in the answer of related problem: Visual Studio Debugger displays wrong values for native types
- Debug Information format is "Program Database" (/Zi). Switching to a different format doesn't solve it
- Struct member alignment is the same in all projects. Searching for similar issues online showed one case where such alignment could be the cause. I checked all the relevant project settings. Every "#pragma pack(1)" is followed by a "#pragma pack()"
- There is no other variable named "mState" (mentioned in Visual Studio showing wrong values while debugging?)
- The following settings are turned off: "Enable Just My Code", "Use Managed Compatibility Mode"
How to solve the problem locally
- Add "auto tempState = mState" before a switch statement. The tempState variable then shows the correct value, while mState is still wrong.
- Adding an indirection:
void MachineControl::onEventReceived(const Evt& event)
{
usessIndirection(event);
}
void MachineControl::uselessIndirection(const Evt& event)
{
switch (mState)
{
//...
}
//...
}
Those two "solutions" are not satisfactory because I don't want to add local variables and unnecessary function calls everywhere just to make debugging work as expected. There seems to be an underlying issue that needs attention.
This issue is really messing up my debugging efforts and I'd be really happy to hear any suggestions or follow-up questions. Thanks!

