Bug 5602 - async method miscompilation when await's return value is not used (have workaround)
Summary: async method miscompilation when await's return value is not used (have worka...
Status: RESOLVED FIXED
Alias: None
Product: Compilers
Classification: Mono
Component: C# ()
Version: unspecified
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Marek Safar
URL:
Depends on:
Blocks:
 
Reported: 2012-06-10 20:50 UTC by Martin Baulig
Modified: 2012-06-11 07:14 UTC (History)
1 user (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 FIXED

Description Martin Baulig 2012-06-10 20:50:24 UTC
With mcs from commit 05a45ba7 (Jun 7th), mcs creates invalid IL code
for this async method:

====
using System;
using System.Threading.Tasks;

class X
{
	internal async Task<int> ExecuteInternalAsync ()
	{
		return 1;
	}

	public async Task<object> ExecuteReaderAsync ()
	{
		await ExecuteInternalAsync ();
		return null;
	}
}
=====

This happens when the await'ed task has a different type the method's return type.

Generated IL code:

======

    // method line 6
    .method public final virtual hidebysig newslot 
           instance default void MoveNext ()  cil managed 
    {
        // Method begins at RVA 0x2100
        // Code size 170 (0xaa)
        .maxstack 3
        .locals init (
                unsigned int32  V_0,
                object  V_1,
                class [mscorlib]System.Exception        V_2)
        IL_0000:  ldarg.0 
        IL_0001:  ldfld int32 X/'<ExecuteReaderAsync>c__async1'::$PC
        IL_0006:  stloc.0 
        IL_0007:  ldarg.0 
        IL_0008:  ldc.i4.m1 
        IL_0009:  stfld int32 X/'<ExecuteReaderAsync>c__async1'::$PC
        .try { // 0
          IL_000e:  ldloc.0 
          IL_000f:  switch (
            IL_0021,
            IL_0065)
          IL_001c:  leave IL_00a9

          IL_0021:  ldarg.0 
          IL_0022:  ldarg.0 
          IL_0023:  ldfld class X X/'<ExecuteReaderAsync>c__async1'::$this
          IL_0028:  call instance class [mscorlib]System.Threading.Tasks.Task`1<int32> class X::ExecuteInternalAsync()
          IL_002d:  callvirt instance valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<!0> class [mscorlib]System.Threading.Ta
sks.Task`1<int32>::GetAwaiter()
          IL_0032:  stfld valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32> X/'<ExecuteReaderAsync>c__async1'::$awaiter0
          IL_0037:  ldarg.0 
          IL_0038:  ldflda valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32> X/'<ExecuteReaderAsync>c__async1'::$awaiter
0
          IL_003d:  call instance bool valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32>::get_IsCompleted()
          IL_0042:  brtrue IL_0065

          IL_0047:  ldarg.0 
          IL_0048:  ldc.i4.1 
          IL_0049:  stfld int32 X/'<ExecuteReaderAsync>c__async1'::$PC
          IL_004e:  ldarg.0 
          IL_004f:  ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<object> X/'<ExecuteReaderAsync>c__async1'::$builder
          IL_0054:  ldarg.0 
          IL_0055:  ldflda valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32> X/'<ExecuteReaderAsync>c__async1'::$awaiter0
          IL_005a:  ldarg.0 
          IL_005b:  call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<object>::AwaitUnsafeOnCompleted<valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32>, valuetype X/'<ExecuteReaderAsync>c__async1'> ([out] !!0&, [out] !!1&)
          IL_0060:  leave IL_00a9

          IL_0065:  ldarg.0 
          IL_0066:  ldflda valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32> X/'<ExecuteReaderAsync>c__async1'::$awaiter0
          IL_006b:  call instance !0 valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1<int32>::GetResult()
          IL_0070:  stloc.1 
          IL_0071:  ldnull 
          IL_0072:  stloc.1 
          IL_0073:  leave IL_0078

          IL_0078:  leave IL_0096

        } // end .try 0
        catch class [mscorlib]System.Exception { // 0
          IL_007d:  stloc.2 
          IL_007e:  ldarg.0 
          IL_007f:  ldc.i4.m1 
          IL_0080:  stfld int32 X/'<ExecuteReaderAsync>c__async1'::$PC
          IL_0085:  ldarg.0 
          IL_0086:  ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<object> X/'<ExecuteReaderAsync>c__async1'::$builder
          IL_008b:  ldloc.2 

          IL_008c:  call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<object>::SetException(class [mscorlib]System.Exception)
          IL_0091:  leave IL_00a9

        } // end handler 0
        IL_0096:  ldarg.0 
        IL_0097:  ldc.i4.m1 
        IL_0098:  stfld int32 X/'<ExecuteReaderAsync>c__async1'::$PC
        IL_009d:  ldarg.0 
        IL_009e:  ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<object> X/'<ExecuteReaderAsync>c__async1'::$builder
        IL_00a3:  ldloc.1 
        IL_00a4:  call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<object>::SetResult(!0)
        IL_00a9:  ret 
    } // end of method <ExecuteReaderAsync>c__async1::MoveNext
======

The error is at offset 0x70
Comment 1 Martin Baulig 2012-06-10 20:58:59 UTC
The problem goes away if you do something with await's return value, ie. store it in a local variable.
Comment 2 Marek Safar 2012-06-11 07:14:03 UTC
Fixed in master