Strange debugger behaviour in async method - c#

When I stepped over breakpoints in my code I have encountered strange behaviour of debugger:
public async Task DoSomeWork()
{
await Task.Run(() => { Thread.Sleep(1000); });
var test = false;
if (test)
{
throw new Exception("Im in IF body!");
}
}
Debugger goes into if body. It's remarkable that the exception is not really thrown but just looks like it is. So you can't reproduce that if you place breakpoint right on throw. You must place it above and step down to the if body to catch it. The same works on any kind of exception instance (as well as explicit null) and even on return instead of throw.
Besides that it works even if I remove line with await.
I tried to run this code snippet from different PCs so its not a PC trouble. Also I have thought it is bug in VS code and tried to run it in Rider from JetBrains - the same result.
I'm sure it's the async thing but how it explicitly works?

Your code reproduces the issue easily, in a "Debug" build, using Visual Studio 2015. I had only to add in Program.Main(), with a call to DoSomeWork().Wait();, set a breakpoint in the method and step through it.
As for why it happens, this is undoubtedly due to the combination of the async method being rewritten and the debugging database (.pdb) generated. Similar to iterator methods, adding async to the method causes the compiler to change your method into a state machine. The actual IL that's generated looks only a little bit like the original method. That is, if you look at it, you can identify the key components of the original code, but it's now in a big switch statement that handles what happens as the method returns at each await statement, and then is re-entered with the completion of each awaited expression.
When the program statement appears to be on the throw, it's really at the implicit return statement in the method. It's just that the debugging database for the executable doesn't provide a program statement for that line.
There's a hint, when debugging, that that's what's happening. When you step over the if statement, you'll notice it goes straight to the throw statement. If the if statement block were really being entered, the next program statement line would actually be the opening brace for the block, not the program statement.
You can also add e.g. a Console.WriteLine() at the end of the method, and that will give the debugger enough information to sync up and not show you at the wrong line number.
For additional information on how async methods are handled by the compiler, see Is the new C# async feature implemented strictly in the compiler, and the links provided there (including Jon's series of articles on the topic).

Related

Single line debug breakpoint assert and break

I have to use my own 'DebugBreak' and 'DebugAssert' methods in order to have a single line properly-working break or assert:
[System.Diagnostics.Conditional("DEBUG")] //only relevant while coding
[System.Diagnostics.DebuggerHidden] //force VS to stop on the call to this method instead of inside this method
public static void DebugBreak()
{
System.Diagnostics.Debugger.Break();
}
[System.Diagnostics.Conditional("DEBUG")] //only relevant while coding
[System.Diagnostics.DebuggerHidden] //force VS to stop on the call to this method instead of inside this method
public static void DebugAssert(bool conditionExpected)
{
if (!conditionExpected)
System.Diagnostics.Debugger.Break();
}
These methods work perfectly fine, but since this is so common there must be methods that do this in .NET? I want the VS UI to stop exactly where a condition is reached (a call stack is useless for this purpose) and I only want this to happen while debugging - I have no interest in showing obscure messages to the user. I also don't want "#if DEBUG" littered all over the place.
Edit: There seems to be massive confusion about what I want - I suggest trying one of my methods in a test project to see the exact behavior I'm talking about.
Edit: Please don't vote to close if you don't understand the question.
Edit: It appears not to be possible - looking at the answer here where the same kludgy use of a wrapper method is required:
Can .NET source code hard-code a debugging breakpoint?

If (false == true) executes block when throwing exception is inside

I have a rather strange problem that is occurring.
This is my code:
private async Task BreakExpectedLogic()
{
bool test = false;
if (test == true)
{
Console.WriteLine("Hello!");
throw new Exception("BAD HASH!");
}
}
Seems really simple, it shouldn't hit the Console.WriteLine or the throw.
For some reason it's always hitting the throw.
If I move the throw into its own method then it works fine. My question is how is it ignoring the if block and hitting the throw new Exception:
EDIT 1: I've updated my code to include the signature, I've removed everything not related to this problem and ran it, it still happens.
It seems to be the bug in async method, the code is not actually executed but debugger steps to the line with throw statement. If there are some lines of code before throw statement inside if these lines are ignored, debugger steps only to the line with throw statement.
Also, if you don't use variable - if (false) or if (true == false) then debugger steps to the correct line of code - to the closing curly brace.
This bug has been posted by #Matthew Watson to Visual Studio team (link is not available now).
Also, see similar question - Condition check in async method
EDIT (2017-10-06):
Issue cannot be reproduced in VS 2017 15.3.5 using .Net Framework 4.7. Seems like VS team has fixed this issue.
Just an addendum to the answer, I've recently encountered the same issue, and looked to the actual x86 code in the debugger, and it was generated in a weird way like this (simplified):
// if (...) {
0001: jne 0006
...
0006: jmp 0007
// }
0007: ret
So instead of directly jumping to the last instructions of the method, it does double jump, where I believe the second unconditional jump is mistakenly recognized as a part of the code inside if block.
So I would speculate that this bug might be related to JIT compiler.

postsharp aspects result in exception being thrown at "end" of method

I am using PostSharp in C#, for using AOP in my codebase. Recently i've noticed that errors are not being thrown where they are actually thrown, but at the end of the method which was weaved with any aspect. For example, take the sample code below:
public void methodUsingAspects()
{
doSomething1();
doSomethingWhichThrowsError(); //an error is thrown in this method
doSomething2();
} //in visual studio, while debugging, the debugger stops at this line (end of method), not at the actual line the error got thrown.
The error gets shown as if thrown where there is the last curly bracket }. This is quite frustrating especially when the error is thrown quite deep inside the calls the method does.
I can assume why this is done, since the code is changed - but is it possible to somehow leave it work as it was before?

Knowing in what part the method returned

Is it possible to get run-time information about where a method has returned?
I mean, if the method returned after running all its lines of code, or because of an earlier
return statement that occurred due to some condition.
The scenario is using interceptor for creating UnitOfWork that should exists in method scope.
For example, lets consider this code:
[UnitOfWork]
public void Foo()
{
// insert some values to the database, using repositories interfaces...
DoSomeChangesInTheDataBaseUsingRepositories();
var result = DoSomethingElse();
if (!result) return;
DoMoreLogicBecuseTheResultWasTrue();
}
I have interceptor class that opens thread static unit of work for methods that are flagged with [UnitOfWork] and when the scope of the method ends it run commit on the UoW and dispose it.
This is fine, but lets consider the scenario above, where for some reason a programmer decided to return in the middle of the method due to some condition, and in that scenario the changes made by the repositories should not be persisted.
I know that this can indicate wrong design of the method, but be aware that it is a possible scenario to be written by a programmer and I want to defend my database from these kind of scenarios.
Also, I don't want to add code to the method itself that will tell me where it ended. I want to infer by the method info somehow its returned point, and if it is not at the end of its scope the interceptor will know not to commit.
The simple answer is use BREAKPOINTS and Debugging.
Edit:- As mentioned by Mels in the comments. This could be a useful suggestion.
If your application is very timing-sensitive, set conditional breakpoints such that they never actually stop the flow of execution. They do keep track of Hit Count, which you can use to backtrace the flow of execution.
Just for your attention. From the microsoft site:-
For those out there who have experience debugging native C++ or VB6
code, you may have used a feature where function return values are
provided for you in the Autos window. Unfortunately, this
functionality does not exist for managed code. While you can work
around this issue by assigning the return values to a local variable,
this is not as convenient because it requires modifying your code. In
managed code, it’s a lot trickier to determine what the return value
of a function you’ve stepped over. We realized that we couldn’t do the
right thing consistently here and so we removed the feature rather
than give you incorrect results in the debugger. However, we want to
bring this back for you and our CLR and Debugger teams are looking at
a number potential solutions to this problem. Unfortunately this is
will not be part of Visual Studio 11.
There are a couple ways that normally indicate that a method exited early for some reason, one is to use the actual return value, if the value is a valid result that then your method probably finished correctly, if its another value then probably not, this is the pattern that most TryXXX methods follow
int i;
//returns false as wasn't able to complete
bool passed = int.TryParse("woo", out i);
the other is to catch/trhow an exception, if an exception is found, then the method did not complete as you'd expect
try
{
Method();
}
catch(Exception e)
{
//Something went wrong (e.StackTrace)
}
Note: Catching Exception is a bad idea, the correct exceptions should be caught, i.e NullReferenceException
EDIT:
In answer to your update, if your code is dependant on the success of your method you should change the return type to a boolean or otherwise, return false if unsuccessful
Generally you should use trace logs to watch you code flow if you cant debug it.
You could always do something like this:
private Tuple<int, MyClass> MyMethod()
{
if (condition)
{
return new Tuple<int, MyClass>(0,new MyClass());
}
else if(condition)
{
return new Tuple<int, MyClass>(1, new MyClass());
}
return new Tuple<int, MyClass>(2,new MyClass());
}
This way you´ll have an index of which return was returning your MyClass object. All depends on what you are trying to accomplish and why - which is at best unclear. As someone else mentioned - that is what return values are for.
I am curios to know what you are trying to do...

Moby Dick of exceptions

There are multiple questions (1,2,3,4 etc. etc.) called "Why isn't this exception caught". Sadly, none of these solutions work for me... So I am stuck with a truly uncatchable exception.
I have a piece of code (.NET 4.0) that checks a large textfile for digits and numbers. Whilst testing I got a runtime exception:
What you see here is a try-catch pattern with a catchblock for an ArgumentOutOfRangeException. But during runtime, the try block throws an ArgumentOutOfRangeException that is not being caught.
I read the C# language specification section about the try-catch structure, and it says:
A catch block of a try statement is reachable if the try statement is reachable.
So in theory the above code should catch the exception.
Then I thought it might had something to do with the fact that this code is running in a task (during the processing of the textfile I also want to update the UI so I do it asynchronous). I searched around and then I found this answer by Jon Skeet. Basically suggesting I use Task.Wait in a try-catch block to catch any exceptions.
The problem I am facing now is that I can't really call Task.Wait because that would block the calling thread which is my UI thread! Then I figured that I could create an extra tasklayer to wait for that task:
//Code called from the UI
System.Threading.Tasks.Task.Factory.StartNew(()=>
{
//Create a new task and use this task to catch any exceptions
System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew(MethodWithException);
try
{
task.Wait();
}
catch(Exception)
{
MessageBox.Show("Caught it!");
}
});
But this still gives the same result... Then I thought that it could be because of the fact I am not specific enough with my Exceptiontype. But the C# Language Specification states:
Some programming languages may support exceptions that are not representable as an object derived from System.Exception, although such exceptions could never be generated by C# code.
So unless you use some sketchy third party API you're always good when you use Exception. So I found myself with an suggested answer by Jon Skeet that didn't quite work for me. That's when I knew I should just stop trying...
So does anyone know what is going on? And how can I fix this? I know I could just check if i is equal or bigger than text.Length but understanding what's happening is more important than working code.
This is simply an artifact of the debugger.
In the Debug menu, there's an option called Exceptions... Click it, and make sure to uncheck the "Thrown" checkbox here:
Many times, you'll want to see the error in context, even if it's inside a try/catch, which is what this setting is for. In this case, that is exactly what you ought to be doing, so that you can see compare i to the length of text and see where your problem is.
If you ran the code without the debugger (such as by double-clicking the executable or using the "Start without Debugging" option), you would "correctly" throw away the error without any alerts.
I just wrote the following test:
[TestMethod]
public void ArgumentOutOfRangeExceptionTest()
{
string test = "abc";
int i = 0;
try
{
while (true)
{
test.ElementAt(i);
i++;
}
}
catch (ArgumentOutOfRangeException)
{ }
}
It is working fine. I believe that you had another exception, which is not called in your calling code.
There is only one exception I know which can't be caught. It's the StackOverflowException. See this question about it.

Categories