2013-04-11 112 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