Why does this line cause a VerificationException when running under .NET 4?
Asked Answered
E

1

20

Help me out folks - why does this code cause a VerificationException when run under .NET 4.0?

public  T parseEnum<T>(string value, T defaultValue) {
  //Removing the following lines fixes the problem
  if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
  return defaultValue;
}

I ran peverify on the .net 2.0 assembly and got the following message:

ImageResizer.Util.Utils::parseEnum[T]][offset 0x0000000A] The 'this' parameter to the call must be the calling method's 'this' parameter.

This causes a VerificationException: Operation could destabilize the runtime message when running the code under medium trust.

I've already read all the similar-looking posts on stack overflow, and none of them apply to this code.

Is there something new with generics that would cause this code to be somehow invalid?

Entomophagous answered 2/8, 2011 at 23:7 Comment(6)
I just ran this code and received no such exception. Are you sure this is where the error lies? Is this being used in asp?Greenockite
Are you generating the .NET assembly using Visual Studio or another compiler (like Mono)?Winnebago
The error message indicates to me that it is at the call site (i.e. where you are calling the method) that is having this problem. Can you show us that code as well?Airstrip
The assembly is generated using VS 2010. Run the code in low trust to reproduce the error. Here's an example of calling code: `totalBehavior = parseEnum<TotalSizeBehavior>("sizelimits.totalbehavior", TotalSizeBehavior.ThrowException);Entomophagous
Also, I've discovered peverify chokes only when the line if (!typeof(T).IsEnum) is present in the method.Entomophagous
Try adding static to the method: the method doesn't appear to use any instance fields and the verification appears to be failing because the method is an instance method.Holzman
E
33

The underlying reason for the error is a change in the signature of IsEnum.

In .NET 2.0 (and 3.0), IsEnum wasn't a virtual method:

public bool IsEnum { get; }

The assembly emitted to call it is:

call instance bool [mscorlib]System.Type::get_IsEnum()

In .NET 4.0, IsEnum is a virtual method:

public virtual bool IsEnum { get; }

Here is the same line of assembly for 4.0:

callvirt instance bool [mscorlib]System.Type::get_IsEnum()

The error you're getting was added in peverify just before the 2.0 release, and warns when a virtual method is called non-virtually.

Now, peverify loads up your code, loads .NET 4.0, and then checks your code. Since your code calls the (.NET 4.0) virtual method non-virtually, the error is shown.

One would think that since you're building against the .NET 2.0 version, this should be fine, and it would load the .NET 2.0 CLR to check. It doesn't seem so.

Edit:

In order to check this, I downloaded .NET 2.0's SDK and tried the peverify in there. It correctly verifies the code.

So the message would seem to be this: use a peverify which matches the target framework of your code.

Solution:

It seems that the _Type interface provides a solution to this:

if (((_Type)typeof(T)).IsEnum) ...

The documentation says it is designed to be called from unmanaged code, but as a side effect of it being an interface, it provides a stable (virtual) method to call.

I have confirmed that it works with peverify whether you target 2.0 or 4.0.

Endemic answered 3/8, 2011 at 3:5 Comment(2)
Thanks - it makes sense. My assemblies are targeting both the .NET 2.0 and .NET 4.0 frameworks, so I guess I simply can't call IsEnum, correct?Entomophagous
Actually, there is a _Type interface which says it is "version independent". It might have been designed to work around issues like this. I'll add it to the answer.Endemic

© 2022 - 2024 — McMap. All rights reserved.