在奇怪的情况下抛出AccessViolationException异常。

9

我已经学习C#很长时间了,但从未遇到过这种错误。首先,除了逻辑有误(我知道它总是返回0),你看到这个代码块有什么问题(可能有问题)吗?

public static int GetDecimals(MySimpleEnum val)
    {
        int result = 0;
        switch (val)
        {
            case MySimpleEnum.Base:
            case MySimpleEnum.Slow:
            case MySimpleEnum.Normal:
            case MySimpleEnum.Quick:
            case MySimpleEnum.Fastest:
                result = 0;
                break;
        }            
        return result;        
    }

释放项目设置:DEBUG常量=false; TRACE常量=true; 优化代码=true; 输出/高级/调试信息=无; IIS=版本7.5
指定了释放设置的此方法会抛出“System.AccessViolationException:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”。
有趣的部分在于,在以下情况下它不会抛出此异常:
1. 在IIS(Express和非Express)8.5上运行(不需要进行项目编辑)。 2. 将Optimize code=false;和Output/Advanced/Debug info=false; 3. 将方法包装在try/catch块内(还尝试使用catch块中的log4net记录异常-空日志)。 4. 用一些不同的代码替换方法的内部。
请注意以下几点:
1. 必须使用win调试器在服务器上捕获异常(没有调用常规.NET异常处理程序) 2. 应用程序在异常后崩溃。 3. 这个代码块几个月前就开始运作了(很长时间没有发布)。该错误可能随着某些更新而开始。 4. 在具有IIS 7.5和具有IIS 8.5和IIS Express(VS2012)的一个机器上测试。相同的结果。 5. 我尝试了许多不同的项目设置组合。基本上,如果我不像第2点那样设置设置,则会在IIS 7.5上引发异常。 6. 我的工作(和构建)机器正在运行最新更新的Windows 8.1。 7. 该代码块位于单独的项目(类库)中。
我知道如何解决这个问题。但是,我不喜欢在不知道原因的情况下关闭问题。而且,我想避免在将来发生这种情况。如果它是一些空引用异常,为什么会发生这种情况?为什么它与调试/发布特定或IIS版本特定有关?
*注2: 最近,在发布时我遇到了缺少dll的问题(System.Net.Http.Formatting.dll、System.Web.Http.dll、System.Web.Http.WebHost.dll)。这是因为某个Microsoft安全更新。也许这是类似的问题。*
编辑1 添加枚举声明的结构。
public enum MySimpleEnum
    {
        Base = 0,
        Slow = 1,
        Normal = 2,
        Quick = 3,
        Fastest = 4
    }

另外,我刚刚尝试添加 [MethodImpl(MethodImplOptions.NoInlining)],但没有帮助。

我认为我们需要看一下调用该函数的上下文! - Phill
为什么我倾向于说这个方法的本质是毫无意义的。我并不是用一种贬低的方式来说,但你创建了一个局部作用域变量并将其设置为零,然后进行一个开关操作,该操作将内联到始终将局部变量设置为零,然后返回一个从零开始、被设置为零并将作为零返回的值。我不太确定编译器会如何内联该函数,但我倾向于认为它会将其优化为“return 0;”,并忽略你代码的其余部分。这是实际的函数吗?你真的使用它吗?我只是不明白它的意义,因为它什么也没做。 - Tyler Durden
@TylerHarden 我被分配到一个旧项目,里面有很多糟糕的代码。这是其中一个例子。我不知道为什么会创建这个方法。它就在那里。尽管我没有动它,但它开始抛出错误。但也许你说得对,优化可能存在一些 bug。 - Martin Brabec
抱歉,Martin,我没有注意到你问题中的日期。我只是在寻找未回答的C#和ASP.NET问题,以尝试提供帮助,然后注意到了标题。你最终找到解决方案了吗? - Tyler Durden
@TylerHarden 没问题,无论如何还是谢谢 :-) 不,我没有找到解决办法.. 但考虑到赞数,看起来我可能不是唯一一个有这个问题的人。所以也许这是一些编译器优化的 bug.. - Martin Brabec
显示剩余2条评论
2个回答

4
这种访问冲突错误在托管代码中很不寻常。它们来自于内存损坏,这可能表明硬件故障——在极少数情况下,这意味着CLR本身存在漏洞。
最有可能引起此类错误的原因来自其他地方,例如,如果此代码以某种方式使用本机代码——无论是在不安全的上下文中调用本机代码还是从本机代码中调用。
引用MSDN AccessViolationException的话:

在完全由可验证的托管代码组成的程序中,所有引用都是有效的或为null,并且无法发生访问冲突。只有当可验证的托管代码与不受控制的代码或不安全的托管代码交互时,才会发生AccessViolationException。

在任何情况下,您通常需要在代码中查找破坏内存的错误代码。不幸的是,这是一个相当棘手的问题。祝你好运!

1

我不确定这对你是否仍然相关,但我成功地通过在完全托管的代码部分中更改一个非常小且无关紧要的布尔值来生成了这个AccessViolation错误。 然而最好的部分是,如果我在编译器中禁用该子项目的代码优化,一切都可以正常运行。这似乎是编译器在一种非常特定的情况下引入的错误,它并不需要有任何逻辑意义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接