Bug 53688 - Method not called from async/await foreach loop
Summary: Method not called from async/await foreach loop
Status: RESOLVED INVALID
Alias: None
Product: Class Libraries
Classification: Mono
Component: System ()
Version: 4.2.1 (C6SR0)
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-03-21 23:29 UTC by bramkamies
Modified: 2017-03-22 00:01 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED INVALID

Description bramkamies 2017-03-21 23:29:47 UTC
mono --version
Mono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug
        LLVM:          supported, not enabled.
        GC:            sgen


Making a http server using HttpListener and async/await.
After receiving a request, the code runs this method:

```
private async Task HandleClient(HttpListenerContext context)
{
	try
	{
		Console.WriteLine($"Request: {context.Request.Url}");
		foreach (KeyValuePair<HttpRoute, RequestHandler> route in _routing)
		{
			if (route.Key.CanAccept(context.Request))
			{
				Console.WriteLine($"Handler: {route.Value.GetType()}");
				await route.Value.HandleRequest(context);
				Console.WriteLine($"Handler done: {route.Value.GetType()}");
				break;
			}
		}
	}
	finally
	{
		Console.WriteLine($"Closing: {context.Request.Url}");
		context.Response.OutputStream.Close();
	}
}
```

When this method executes, it prints the following:

Request: http://some.uri/path
Handler: MyHandlerClass
Closing: http://some.uri/path

The contents of the HandleRequest() is as follows:

```
public Task HandleRequest(HttpListenerContext context)
{
	Console.WriteLine("Enter");
	return Task.Completed;
}
```

Note: Enter does not get called at all, nor the printstatement directly following it.
Using dnSpy I found that the first method is effectively transformed into:

```
void IAsyncStateMachine.MoveNext()
{
	int num = this.<>1__state;
	try
	{
		if (num != 0)
		{
		}
		try
		{
			if (num != 0)
			{
				Console.WriteLine(string.Format("Request: {0}", this.context.Request.Url));
				this.<>s__1 = this.<>4__this._routing.GetEnumerator();
			}
			try
			{
				TaskAwaiter taskAwaiter;
				if (num != 0)
				{
					while (this.<>s__1.MoveNext())
					{
						this.<route>5__2 = this.<>s__1.Current;
						bool flag = this.<route>5__2.Key.CanAccept(this.context.Request);
						if (flag)
						{
							Console.WriteLine(string.Format("Handler: {0}", this.<route>5__2.Value.GetType()));
							taskAwaiter = this.<route>5__2.Value.HandleRequest(this.context).GetAwaiter();
							if (!taskAwaiter.IsCompleted)
							{
								num = (this.<>1__state = 0);
								this.<>u__1 = taskAwaiter;
								Server.<HandleClient>d__6 <HandleClient>d__ = this;
								this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Server.<HandleClient>d__6>(ref taskAwaiter, ref <HandleClient>d__);
								return;
							}
							goto IL_11C;
						}
						else
						{
							this.<route>5__2 = default(KeyValuePair<HttpRoute, RequestHandler>);
						}
					}
					goto IL_16B;
				}
				taskAwaiter = this.<>u__1;
				this.<>u__1 = default(TaskAwaiter);
				num = (this.<>1__state = -1);
				IL_11C:
				taskAwaiter.GetResult();
				taskAwaiter = default(TaskAwaiter);
				Console.WriteLine(string.Format("Handler done: {0}", this.<route>5__2.Value.GetType()));
				IL_16B:;
			}
			finally
			{
				if (num < 0)
				{
					((IDisposable)this.<>s__1).Dispose();
				}
			}
			this.<>s__1 = default(Dictionary<HttpRoute, RequestHandler>.Enumerator);
		}
		finally
		{
			if (num < 0)
			{
				Console.WriteLine(string.Format("Closing: {0}", this.context.Request.Url));
				this.context.Response.OutputStream.Close();
			}
		}
	}
	catch (Exception exception)
	{
		this.<>1__state = -2;
		this.<>t__builder.SetException(exception);
		return;
	}
	this.<>1__state = -2;
	this.<>t__builder.SetResult();
}
```

This problem does not occur on windows, but it does happen when I run it on ubuntu mono.
Repo: https://github.com/Nuterra/YinYang/tree/mono-debug
Comment 1 bramkamies 2017-03-21 23:49:29 UTC
Fixed; the method would not compile and the try/finally was eating the exception so I never noticed.

Sorry
Comment 2 bramkamies 2017-03-22 00:01:47 UTC
Note: the crash was because Task.CompletedTask was inaccessible, although I was targetting 4.6.1