RESOLUTION
To resolve this problem, obtain the latest service pack for Microsoft .NET Framework. For additional information, click the following article number to view the article in the
Microsoft Knowledge Base:
318836 INFO: How to Obtain the Latest .NET Framework Service Pack
NOTE: to see the proper stepping behavior, you must recompile your code after you have installed the service pack.
MORE INFORMATION
Example 1
The following code sample is a
try-catch-finally construct:
try
{
Console.WriteLine("In try");
}
catch(Exception e)
{
Console.WriteLine("In catch");
}
finally
{
Console.WriteLine("In finally");
}
Assume that the debugger is stopped at the following line:
Console.WriteLine("In try");
When the next step occurs, it appears that the debugger has stepped into the
catch block. However, the following output of the construct shows that this is not actually the case:
In try
In finally
In this example, the instruction that causes the error is a
CEE_LEAVE instruction in the
try block. If you use Ildasm.exe to view the IL that is generated for the instruction, the instruction appears as the following:
leave.s <some line number>
This instruction has no associated source line; however, when the debugger steps into this instruction, the debugger shows the source information of the lexically previous instruction that had associated source code. In this example, this is the following source line:
Console.WriteLine("In catch");
Example 2
The following example is a nested
if construct:
bool testCond = true;
if (testCond)
{
if (!testCond)
{
Console.WriteLine("Appears to step, but doesn't execute");
}
}
else
Console.WriteLine("Doesn't execute, and doesn't stop here");
When the debugger steps through this code, the debugger appears to run to the inner
if statement. As in example 1, however, the debugger is not actually running the code, and no output is generated.
In example 2, the instruction that causes the error is a
CEE_BR instruction. When you use Ildasm.exe, the instruction appears at the end of the
true clause of the
if (testCond) statement as follows:
br.s <some line number>
This instruction has no associated source line; therefore, when the debugger steps into this instruction, the following line appears to be run, even though it is not:
Console.WriteLine("Appears to step, but doesn't execute");
This occurs only if the instructions that precede the
CEE_BR instruction (that is, instructions that are generated by compiling the
true clause) are not run because the
true clause in which the instructions are found is not run.
WORKAROUND
To work around this problem, use any of the following three methods:
- Set breakpoints around the block of code that you believe is causing the problem to determine whether the instructions are actually being run.
That is, set a breakpoint on the first line of the erroneous construct (the line of code that you believe is not running) and on the next line that should be run. When the debugger reaches the first breakpoint, either press F5, or click Continue on the Debug menu. If the code is truly not being run, the next breakpoint that the debugger reaches is the next line that should be run.
In example 1, set a breakpoint at each of the following lines:
Console.WriteLine("In try");
Console.WriteLine("In catch");
Console.WriteLine("In finally");
When the debugger reaches the breakpoint that is associated with the following line, either press F5 or select Continue from the Debug menu:
Console.WriteLine("In try");
Note that the next breakpoint that the debugger reaches is the breakpoint that is associated with the following line:
Console.WriteLine("In finally");
With this workaround, you can test a suspect block of code to determine whether it is really running.
- Examine data in the Disassembly window. When the source level stepping appears to be incorrect, you can consult the assembly level stepping information.
In example 2, switch to the Disassembly window when the currently stopped source line appears to be the following:
Console.WriteLine("Appears to step, but doesn't execute");
Note that the current run point is actually a jmp address instruction, and that this instruction occurs after the following line:
Console.WriteLine("Appears to step, but doesn't execute");
- In most cases, you can mitigate the instructions that cause the problem by rewriting that particular code construct. To do this, you must usually either add a dummy line of code, or rewrite the code in an unnatural way.
For example, you can rewrite the code for example 1 as follows:
try
{
try
{
Console.WriteLine("In try");
} catch(Exception e)
{
Console.WriteLine("In catch");
}
// A dummy line of code.
int i = 5;
}
finally
{
Console.WriteLine("In finally");
}
Note that the stepping behavior now performs as expected. In general, in a try-catch-finally case, you must split the construct into a try-finally construct that contains a try-catch construct, and add a dummy line of code after the catch block and before the erroneous leave instruction.
You can rewrite the code for example 2 as follows:
bool testCond = true;
if (testCond)
{
if (!testCond)
{
Console.WriteLine("Appears to step, but doesn't execute");
}
// A dummy line of code.
int i = 5;
}
else
Console.WriteLine("Doesn't execute, and doesn't stop here");
Note that the stepping behavior now performs as expected. In general, in a nested if situation, you must insert a dummy line of code after the inner if and before the erroneous branch instruction.