why does visual studio do this?

Started by
11 comments, last by RobTheBloke 8 years, 3 months ago

Do you have any tips to share?

When I come across Release build bugs, I often feel like my only recourse is to insert various logging statements to narrow down what's going on.
This obviously doesn't always help, and can even mask the bug entirely if it's a race condition and the logging statements affect timing, etc...


Most compilers have options to generate debugging information into release builds, which will help.

Other than that, you're just going to have to get familiar with your target system's assembly language and calling convention. If something looks fishy when debugging it with the debugger (and detecting "fishy" can take some practice) then drop down to the assembly view and see if you can trace to path of data through your function.

Sometimes you'll have gone too far or detected the bug too late and the data is long gone (left in a register that was later overwritten), in which case you'll have to see if you can detect it earlier and reproduce it again.

And sometimes you'll just have to save off a dump + memory dump, the debugging information and executable, and your notes, and hope the issue comes up again so you can start to find some patterns.

Of course, source control can also help, if you know a build that is good, you can do a binary search of checkins between the good and bad build to find the checkin that introduced the bug, which can help you track it down.
Advertisement


Do you have any tips to share?

SmkViper covered most of it. It's not all as bad as he indicates (most of the debugging experience is quite pleasant for code built with modern compilers with symbol generation enabled, e.g. the /Zo flag on MSC or the standard GCC -g behavior). It's good enough that I usually turn on light optimizations for "debug" builds (-Og is only available in GCC after all) because the extra speed is worth the very minor inconviences when debugging.

In general, though, you absolute do need to learn assembly (just how to read it; only madmen from planet crazypants _write_ assembly in any large quantity anymore) and understand your system's calling convention(s) and how your compiler and linker and such all actually work under the hood. For example, know that on x86 the `this` value for a C++ member function is passed in the ECX register. Then also know that some compilers have a tendency to promptly MOV ESI, ECX (and know that that means "copy the value from the register named ECX into the register named ESI") and leave it there. And so if the debugger is being dumb and isn't properly showing you class variables in scope you probably just have to put (MyClass*)ESI into the watch window. Know the debug memory patterns your runtime spits out and recognize that if you see streams of the 0xCD memory bit pattern in a variable, you forgot to initialize it properly (if using the default debug-enabled Microsoft runtime) and so on.

Mostly, it just boils down to lots and lots of practice and Googling. :)

Sean Middleditch – Game Systems Engineer – Join my team!

That isn't the issue. It won't recompile that cpp for some reason. it's using the old code.

What makes you think that? Debugging is impossible in Release build, so anything it tells you is false.

Wrong way around. Debugging is perfectly possible in release builds, but you need to use the disassembler and understand asm.

Debug builds are deliberately de-optimised. Every variable will be stored within a known memory location (for stack allocated variables, that means they will actually be stored on the stack, rather than a register). If you say something like:

A = b + c

Then the operation of b+c will always result in a store operation.

The debugger therefore only has to look for call or store operations, and break on those instructions. In release builds however, the use of inlining and registers, means that those operations are pretty much eradicated (hopefully, because that means your code is quick).

Debugging in release builds isn't impossible, but it does require either stepping through the disassembly, or usage of compile flags to prevent inlining. Neither are much fun....

This topic is closed to new replies.

Advertisement