代码之家  ›  专栏  ›  技术社区  ›  Nikolay R

CIL:“操作可能会破坏运行时”异常

  •  1
  • Nikolay R  · 技术社区  · 15 年前

    我玩了一会儿后竖琴,遇到了一个棘手的问题。

    在Silverlight程序集中跟踪IL:

    .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 
    }
    

    触发器System.Security.VerificationException:操作可能会破坏运行时的稳定性。例外。 反射镜分析正常。它可能有什么问题?

    更新1 代码的作用如下:

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

    更新2 我在setter本身中得到指定的异常

    更新3 作为callvirt(notifypropertychanged)进行非静态调用没有帮助

    更新4 注释(用于测试)代码:

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

    用l_e:brtrue.s l_b替换l_e:br.s l_b做了这个技巧,但这是一个无条件的回报——不是我想要的。

    更新5 如果我使用C编译器来模拟所需的行为(我仍然需要用Postshap来实现这一点) 我得到以下信息:

    .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 
    }
    

    注意,有一些细微的区别-额外的br.s跳转到l_和一些奇怪的跳转l e:brtrue.s l b。在编译器版本中,我直接跳转到ret。

    3 回复  |  直到 11 年前
        1
  •  2
  •   Gael Fraiteur    15 年前

    你用过peverify吗?直接使用msil播放时应始终运行此实用程序(可以使用msbuild标志/p:postsharpverify=true)。

    查看您的代码:

    1. 本地变量未初始化(缺少“init”关键字)。这是methodBodyDeclaration的属性。

    2. 您使用的是“leave”而不是“jmp”,而不是受保护块之外的“jmp”;这是无用的,但不重要。

    祝你好运,

    盖尔

        2
  •  0
  •   Andrew Hare    15 年前

    很难说-你有堆栈跟踪吗?当CLR无法验证代码的类型安全性时,通常会引发此异常。由于这可能来自此代码或您正在使用的任何方法或类型,因此在没有堆栈跟踪的情况下很难确定问题是什么。

        3
  •  0
  •   Dave Swersky    15 年前

    Here's 处理那个错误的帖子。我不知道您的特定情况是否是由同一个问题引起的,但一般来说,这似乎与代码访问安全性和验证有关。如果是这样的话,Reflector可以很好地读取IL,但是CAS系统会因为未知的原因将其踢出。

    看起来您有一个属性设置器调用了一堆其他对象。您应该通过其他方法调用来查找大型switch语句,以防这是post中提到的特定问题。