views:

810

answers:

3

Hi!

I've been playing with PostSharp a bit and I ran into a nasty problem.

Following IL in Silverlight assembly:

.method public hidebysig specialname newslot virtual final instance void 
set_AccountProfileModifiedAt(valuetype [mscorlib]System.DateTime 'value') cil managed
{
    .maxstack 2
    .locals (
        [0] bool ~propertyHasChanged,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: nop 
    L_0002: ldarg.0 
    L_0003: call instance valuetype [mscorlib]System.DateTime 

Accounts.AccountOwner::get_AccountProfileModifiedAt()
    L_0008: ldarg.1 
    L_0009: call bool [mscorlib]System.DateTime::op_Inequality(valuetype 

[mscorlib]System.DateTime, valuetype [mscorlib]System.DateTime)
    L_000e: stloc.0 
    L_000f: ldarg.0 
    L_0010: ldarg.1 
    L_0011: stfld valuetype [mscorlib]System.DateTime 

Accounts.AccountOwner::accountProfileModifiedAt
    L_0016: br.s L_0018
    L_0018: ldloc.0 
    L_0019: ldc.i4.0 
    L_001a: ceq 
    L_001c: stloc.1 
    L_001d: ldloc.1 
    L_001e: brtrue.s L_002b
    L_0020: ldarg.0 
    L_0021: ldstr "AccountProfileModifiedAt"
    L_0026: call instance void 

Accounts.AccountOwner::NotifyPropertyChanged(string)
    L_002b: nop 
    L_002c: leave.s L_002e
    L_002e: ret 
}

triggers System.Security.VerificationException: Operation could destabilize the runtime. exception. Reflector parses it OK. What could be wrong with it?

Update 1 Code is intended to work as follows:

public void set_AccountProfileModifiedAt(DateTime value)
{
    bool propertyHasChanged = this.AccountProfileModifiedAt != value;
    this.accountProfileModifiedAt = value;
    if (propertyHasChanged)
    {
        this.NotifyPropertyChanged("AccountProfileModifiedAt");
    }
}

Update 2 I get specified exception inside the setter itself

Update 3 Making non-static calls as callvirt (NotifyPropertyChanged) does not help

Update 4 Commenting out (for test purposes) code:

L_0018: ldloc.0 
L_0019: ldc.i4.0 
L_001a: ceq 
L_001c: stloc.1 
L_001d: ldloc.1

and replacing L_001e: brtrue.s L_002b with L_001e: br.s L_002b does the trick but it's an unconditional return - not what I want.

Update 5 If I use C# compiler to mimic required behavior (I still need to do that with Postsharp) I get following IL:

.method public hidebysig specialname newslot virtual final instance void 

set_AccountProfileModifiedAt(valuetype [mscorlib]System.DateTime 'value') cil managed
{
    .maxstack 2
    .locals init (
        [0] bool val,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: call instance valuetype [mscorlib]System.DateTime 

Accounts.AccountOwner::get_AccountProfileModifiedAt()
    L_0007: ldarg.1 
    L_0008: call bool [mscorlib]System.DateTime::op_Inequality(valuetype 

[mscorlib]System.DateTime, valuetype [mscorlib]System.DateTime)
    L_000d: stloc.0 
    L_000e: ldarg.0 
    L_000f: ldarg.1 
    L_0010: stfld valuetype [mscorlib]System.DateTime 

Accounts.AccountOwner::accountProfileModifiedAt
    L_0015: ldloc.0 
    L_0016: ldc.i4.0 
    L_0017: ceq 
    L_0019: stloc.1 
    L_001a: ldloc.1 
    L_001b: brtrue.s L_0029
    L_001d: ldarg.0 
    L_001e: ldstr "AccountProfileModifiedAt"
    L_0023: call instance void 

Accounts.AccountOwner::NotifyPropertyChanged(string)
    L_0028: nop 
    L_0029: ret 
}

Note there are minor differences - extra br.s jump at L_0016 and some strange jump L_001e: brtrue.s L_002b. In compiler version I get direct jump to ret.

A: 

It is difficult to say - do you have a stack trace? This exception is usually thrown when the CLR is unable to verify the type-safety of your code. As this could have come from this code or from any of the methods or types you are using it will be difficult to say what the issue is without a stack trace.

Andrew Hare
Top of stack is just a property setter :( : System.Security.VerificationException: Operation could destabilize the runtime. at Domain.Accounts.AccountOwner.set_AccountProfileModifiedAt(DateTime value)
Nikolay R
A: 

Here's a post that deals with that error. I don't know if your particular case is caused by the same problem, but in general it looks like this has to do with code access security and verification. If that's the case, Reflector will be able to read the IL just fine but the CAS system will kick it out for reasons unknown.

It looks like you have a property setter calling into a bunch of other objects. You should go through those other method calls looking for big switch statements, in case it is the specific issue mentioned in the post.

Dave Swersky
This is how it looks like:bool propertyHasChanged = this.AccountProfileModifiedAt != value; this.accountProfileModifiedAt = value; if (propertyHasChanged) { this.NotifyPropertyChanged("AccountProfileModifiedAt"); }IMO it should not fail in setter if some other method fails?
Nikolay R
The exception may be caused by one of the other methods/properties you are accessing. As a test, try pulling all the code out of the setter and see if that fixes it. Then add the code back bit by bit to figure out exactly what's failing.
Dave Swersky
+2  A: 

Did you use peverify? You should always run this utility when playing directly with MSIL (you can use the msbuild flag /p:PostSharpVerify=true).

Looking at your code:

  1. Your local variables are not initialized (missing "init" keyword). This is a property of MethodBodyDeclaration.

  2. You are using a 'leave' instead of a 'jmp' out of a protected block; this is useless but should not matter.

Good luck,

-gael

Gael Fraiteur