Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.AccessViolationException on methods with generic arguments with type constraints #342

Closed
ociaw opened this issue Jul 8, 2020 · 3 comments · Fixed by #343
Closed
Labels
Milestone

Comments

@ociaw
Copy link

ociaw commented Jul 8, 2020

When run with NullGuard, the code below throws a System.AccessViolationException. This is caused by invalid IL weaved by Fody, as it does not box the argument (which can be a struct) before checking it for null. The argument is only not boxed when a generic type constraint is present.

class Program
{
    static void Main()
    {
        Class.Generic(new Implementation());
    }
}
public static class Class
{
    public static void Generic<T>(T implementation) where T : IInterface { }
}

public interface IInterface { }

struct Implementation : IInterface { }

Install Fody and NullGuard.Fody, then run dotnet run --framework netcoreapp3.1.

Full solution

Configuration

I've tested this on:
OS: Windows 10 1903 (10.0.18362)
.NET Core 3.1 and .NET Framework 4.7.2
x86 and x64
Fody 6.2.0
NullGuard.Fody 2.2.0 and 3.0.0-beta1

Other information

Exception thrown:

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Class.Generic[[Implementation, Repro, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]](Implementation)
   at Program.Main()

IL after weaving by Fody (note the lack of boxing before btrue.s):

.method public hidebysig static 
	void Generic<(IInterface) T> (
		!!T implementation
	) cil managed 
{
	// Method begins at RVA 0x2074
	// Code size 20 (0x14)
	.maxstack 2

	IL_0000: ldarg.0
	IL_0001: brtrue.s IL_0013

	IL_0003: ldstr "implementation"
	IL_0008: ldstr "[NullGuard] implementation is null."
	IL_000d: newobj instance void [System.Runtime]System.ArgumentNullException::.ctor(string, string)
	IL_0012: throw

	IL_0013: ret
} // end of method Class::Generic

If the type constraint is removed, the argument is boxed correctly:

.method public hidebysig static 
	void Generic<T> (
		!!T implementation
	) cil managed 
{
	// Method begins at RVA 0x2074
	// Code size 25 (0x19)
	.maxstack 2

	IL_0000: ldarg.0
	IL_0001: box !!T
	IL_0006: brtrue.s IL_0018

	IL_0008: ldstr "implementation"
	IL_000d: ldstr "[NullGuard] implementation is null."
	IL_0012: newobj instance void [System.Runtime]System.ArgumentNullException::.ctor(string, string)
	IL_0017: throw

	IL_0018: ret
} // end of method Class::Generic
@SimonCropp
Copy link
Member

@ociaw have you made any progress on a PR that fixes this?

@ociaw
Copy link
Author

ociaw commented Jul 10, 2020

I've been having trouble writing a test to reproduce the exception, but I was planning on doing the same as #343.

@tom-englert tom-englert added this to the 3.0.0 milestone Jul 11, 2020
@tom-englert
Copy link
Member

The fix is now deployed.
Thanks to @ltrzesniewski for the quick response.

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

Successfully merging a pull request may close this issue.

3 participants