Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

CCRewriter produces invalid IL on async method or iterator blocks #38

Closed
SergeyTeplyakov opened this issue May 5, 2015 · 7 comments
Closed

Comments

@SergeyTeplyakov
Copy link
Contributor

Code Contracts version: 1.7.11202.10 (reproduces on earlier versions as well).
Perform Runtime Contract Checking != Full
Debug/Release: both

Using CCRewrite with Perform Runtime Contract Checking not equals to Full with async method (or methods with iterator blocks) with complex Contract.Requires (that has II or && in it) provides invalid assembly. Using such an assembly leads to System.InvalidProgramExecution exception and peverify shows following error:

[IL]: Error: [PATHToExecutable\CcRewriterBug\bin\Release\CCRewriterBug.exe:
CcRewriterBug.Program+<FooEnumerable>d__3::MoveNext][offset 0x00000021] Stack underflow

Steps to reproduce:

static async Task FooAsync(string str)
{
   // Works fine with Contract.Requires(str != null);
    Contract.Requires(str != null && str.Length > 1);
    await Task.Delay(42);
}

or

static IEnumerable<string> FooEnumerable(string str)
{
    Contract.Requires(str != null && str.Length > 1);
    yield return str;
}

In latter case if Perform Runtime Contract Checking is not Full CCRewrite produces following IL in MoveMethod:

.method private final hidebysig newslot virtual 
    instance bool MoveNext () cil managed 
{
    .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    // Method begins at RVA 0x21ac
    // Code size 64 (0x40)
    .maxstack 2
    .locals init (
        [0] int32 CS$0$0000
    )

    IL_0000: ldarg.0
    IL_0001: ldfld int32 CcRewriterBug.Program/'<FooEnumerable>d__0'::'<>1__state'
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: switch (IL_001a, IL_0037)

    IL_0015: br IL_003e

    IL_001a: ldarg.0
    IL_001b: ldc.i4.m1
    IL_001c: stfld int32 CcRewriterBug.Program/'<FooEnumerable>d__0'::'<>1__state'
    IL_0021: pop // this instruction is invalid!
    IL_0022: ldarg.0
    IL_0023: ldarg.0
    IL_0024: ldfld string CcRewriterBug.Program/'<FooEnumerable>d__0'::str
    IL_0029: stfld string CcRewriterBug.Program/'<FooEnumerable>d__0'::'<>2__current'
    IL_002e: ldarg.0
    IL_002f: ldc.i4.1
    IL_0030: stfld int32 CcRewriterBug.Program/'<FooEnumerable>d__0'::'<>1__state'
    IL_0035: ldc.i4.1
    IL_0036: ret

    IL_0037: ldarg.0
    IL_0038: ldc.i4.m1
    IL_0039: stfld int32 CcRewriterBug.Program/'<FooEnumerable>d__0'::'<>1__state'

    IL_003e: ldc.i4.0
    IL_003f: ret
} // end of method '<FooEnumerable>d__0'::MoveNext```
@Daniel-Svensson
Copy link

It seems like PR #52 fixes these issues

@SergeyTeplyakov
Copy link
Contributor Author

I'll test it, but I don't think that this PR will fix this issue, just because this issue not only with async methods but with iterator blocks, and this issue is happening in VS 2013 with isRoslyn == false.

@SergeyTeplyakov
Copy link
Contributor Author

Tested the fix. Issue is still there.

@danielcweber
Copy link

Can you clarify: You posted two examples, one for async, one for iterators. Does the pull request fix the async example for you ?

@SergeyTeplyakov
Copy link
Contributor Author

As I mentioned, this issue is not related to Roslyn at all and happening in VS2013. So basically this fix is not applicable, because state isRoslyn argument in the Executor is false, so the initial state computed correctly in VS2013 all the time.

I've tested this fix for both async and iterator block and this code still breaks. As I mentioned, this bug is more subtle and to reproduce it you need more complex precondition (using ||, && conditions).

@Daniel-Svensson
Copy link

Hm, my mistake. Read the issue a bit to fast and mistook the inequality for equality. With Perform Runtime Contract Checking == Full it works (but requires the PR for VS2015).

@SergeyTeplyakov SergeyTeplyakov added this to the VS14 Support milestone Jun 25, 2015
SergeyTeplyakov added a commit to SergeyTeplyakov/CodeContracts that referenced this issue Jun 26, 2015
@SergeyTeplyakov
Copy link
Contributor Author

Fixed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants