2013-04-11 82 views
5

堆栈跟踪我从一个ASP.NET应用程序,从ArgumentNullException产生的后退,给出了下面的代码的最后一行出现错误的印象。据我所看到的,那是不可能的,但如果JIT优化了呼叫Bar,这将导致不同的堆栈跟踪,它会说明一切。我知道它不是C#编译器,因为CIL看起来就像我期望的那样。 JIT编译器是否可以删除对Bar的调用?.NET JIT编译器会优化一个方法调用吗?

C#4,.NET 4.0.30319.1,ASP.NET 4.0.30319.1

编辑: 我应该提到,这是一个释放配置,优化代码=开,仅= PDB-调试信息。

Stack Trace: 

[ArgumentNullException: Value cannot be null. Parameter name: value] 
CreateHiddenField(HtmlTextWriter tr, String name, String value) in Foo.cs:129 
Foo(IHttpContext context, HtmlTextWriter writer) in Foo.cs:106 

private static void Foo(IHttpContext context, HtmlTextWriter writer) 
{ // line 103 
    Bar(writer, AuthorizationServerResponseDetailsHttpRequestParser.RequestSAMLFieldName, context); 
    Bar(writer, AuthorizationServerResponseDetailsHttpRequestParser.RequestTargetFieldName, context); 
    // line 106 - blank line in source code. 
    CreateHiddenField(tr, name, string.Empty); // looks like its here 
} 

private static void Bar(HtmlTextWriter tr,string name, IHttpContext context) 
{ // line 116 
    #region Sanitation 
    if (tr == null) { throw new System.ArgumentNullException("tr"); } 
    if (name == null) { throw new System.ArgumentNullException("name"); } 
    if (context == null) { throw new System.ArgumentNullException("context"); } 
    #endregion 

    CreateHiddenField(tr, name, context.RequestQueryString(name)); 
} 

private static void CreateHiddenField(HtmlTextWriter tr, string name, string value) 
{ // line 127 
    #region Sanitation 
    if (tr == null) { throw new System.ArgumentNullException("tr"); } 
    if (name == null) { throw new System.ArgumentNullException("name"); } 
    if (value == null) { throw new System.ArgumentNullException("value"); } 
    #endregion 

    // payload... 
} 
+1

你能提供的堆栈跟踪? JIT可以嵌入一个方法,如果它符合要求 - 这可能导致它从堆栈跟踪中“消失”...我想。 – Joshua 2013-04-11 17:45:34

+0

它在那里,在第一个代码块中。我删除了名称空间/文件名称以使其可读。 – jasper 2013-04-11 17:47:25

+1

什么你知道,我不认为这是因为它是如此之小的堆栈跟踪。我的猜测是它被内联,但我不知道编译器是否发出代码来保留“正确的”堆栈跟踪。堆栈跟踪是否带有任何行号或字节偏移量? – Joshua 2013-04-11 17:57:34

回答

4

http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx,如果抖动内联的方法调用,它的确会在堆栈跟踪崩溃。如果你不希望它内联(这可能不是一个好主意),你可以在方法使用

[MethodImpl(MethodImplOptions.NoInlining)] 

。对于EXE,你也可以使用INI文件来告诉抖动生成跟踪信息(在链接页面的底部),但我不知道如何将一个ASP.NET应用程序的工作。

+0

这正是我一直在寻找,但我无法找到它。 – Joshua 2013-04-11 18:19:59

+0

完美。 URL确认我怀疑的是什么,但是当我搜索时我找不到那篇文章。 – jasper 2013-04-11 18:21:12

2

我从来没有见过的JIT删除方法调用,只是内联它。通常情况下,它会删除未使用的局部变量,但我相当肯定的JIT不能staticly分析所有的副作用从调用一个方法,所以我不认为它永远不会删除方法调用。

我的猜测是将一个空值传递给一个在CreateHiddenField之内调用的方法,该方法碰巧也有一个参数value。由于默认情况下在发布模式中启用了内联,因此您无法真正相信堆栈跟踪(或发生异常的假定行号)。机会是你的问题在于CreateHiddenField或更深的隐形堆栈。 :)

您可以禁用优化以获得堆栈跟踪的一个更好的主意。 MSDN has some instructions here