Sometimes it happens, that Visual Studio debugger shows invalid current instruction. The simplest possible reasons are:
But my case was different. Here's a piece of source code (C#):
if (match.Groups.Count != 4)
throw new InvalidOperationException("Internal error: Invalid regular expression!");
MyEnum myEnum;
try
{
// (...)
I debugged the source. Debugger stopped at the conditional statement and shown, that match.Groups.Count
actually is equal to 4. Obviously, the throw statement should have been skipped, but surprisingly, was not. However, after "executing" the throw
statement, debugger went to the next valid statement and continued executing as it was supposed to.
What happened?
In such cases it is usually worth to look at the disassembly. In my case it looked like:
if (match.Groups.Count != 4)
00000344 mov rax,qword ptr [rbp+30h]
00000348 mov rax,qword ptr [rax]
(...)
00000399 test eax,eax
0000039b jne 00000000000003ED // (1)
throw new InvalidOperationException("Internal error: Invalid regular expression!");
0000039d lea rdx,[00049AC0h]
000003a4 mov ecx,7000024Eh
000003a9 call 000000005F7CC994
(...)
000003dc call 000000005ED32730
000003e1 mov rcx,qword ptr [rbp+000000F8h]
000003e8 call 000000005F7CC64C
000003ed nop // (2)
MyEnum myEnum;
try
{
000003ee nop // (3)
I set the breakpoint at the jne
instruction (1). For those, who don't know the assembler much (not, that I actually do), conditional statements are often compiled to a pair: test
and some kind of conditional jump, such as jne
(jump if not equal). So the place, where I set the breakpoint was actually a final decision, whether to execute the throw statement or not.
After a step-over (F10), debugger jumped to the (2) location, so it correctly skipped the throw statement. Again for those, who doesn't know that, the nop
(No operation) is an assembler instruction, which actually does nothing. Compiler usually uses it to align the assembly code, such that it performs better (low level processor stuff, I guess).
But the compiler screwed up and saved the information in .pdb file, that mentioned nop
is a part of the throw
statement. Debugger read that and positioned the current instruction marker on the throw
statement. But then, it just executed it (did nothing) and kept on executing, because the actual assembly code was correct.
I leave this example in case, that someone finds himself stuck with similar problem - hopefully it'll help to find the cause. It's rather rare to encounter, but who knows?...