天天看點

使用 Windbg 分析一個 異步操作 引發的 Crash 異常

上周我們收到了一個客戶的緊急求助,他們的一個 ​

​iis應用程式池​

​ 經曆了頻繁重新開機,即使從錯誤日志中也不得到任何有用的資訊,異常資訊如下:

System.NullReferenceException : Object reference not set to an instance of an object.
System.Web.ThreadContext.AssociateWithCurrentThread(Boolean)
   System.Web.HttpApplication.OnThreadEnterPrivate(Boolean)
   System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(System.Threading.SendOrPostCallback, System.Object)
   System.Web.LegacyAspNetSynchronizationContext.CallCallback(System.Threading.SendOrPostCallback, System.Object)
   System.Threading.Tasks.AwaitTaskContinuation.RunCallback(System.Threading.ContextCallback, System.Object, System.Threading.Tasks.Task ByRef)
   System.Threading.Tasks.AwaitTaskContinuation+<>c.b__18_0(System.Object)
   System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   System.Threading.ThreadPoolWorkQueue.Dispatch()


      

這種異常會殺掉程序,通過 google 搜尋會發現這是 ​

​.NET 4.5​

​​ 異步操作下的某種經典異常,大概就是說沒有在合适的地方等待 ​

​Task​

​, 參考:https://stackoverflow.com/questions/18759987/async-code-without-waiting-for-completion  ,參考如下代碼:

var getDataTask = getData();

if(some_condition == true) {
    return some_object;
}

getDataTask.Wait();

return getDataTask.result;


      

如果代碼無意走了 ​

​if(some_condition == true)​

​​ 路徑并沒有 ​

​Wait​

​​ 後續的 ​

​getDataTask​

​ 就會抛出這種異常,現在的問題是堆棧資訊太少,并不能找到異常的源頭在哪裡?

使用 windbg 分析

如果你有 crash 的 dump,用windbg就能挖到很多有價值的資訊。

  1. File → Open Crash Dump

首先使用 windbg 打開 crash 檔案,如下圖:

使用 Windbg 分析一個 異步操作 引發的 Crash 異常

從圖中可以看到,windbg 已經告知我們目前有一個 CLR 異常。

  1. Symbols

雖然沒有客戶的 debug 符号,這裡使用微軟的符号伺服器, ​

​srv*C:\symbols*http://msdl.microsoft.com/download/symbols;​

​ 如下圖:

使用 Windbg 分析一個 異步操作 引發的 Crash 異常
  1. 加載 SOS 擴充

在 windbg 指令視窗中輸入  ​

​.loadby sos clr​

​ 。

  1. 異常分析指令

使用 windbg 自帶的異常分析自動化指令 ​

​!analyze -v​

​ ,然後你會得到很多的 異常資訊, 參見下圖:

使用 Windbg 分析一個 異步操作 引發的 Crash 異常

上面的圖中會告訴我們出問題的線程,接下來我們怎麼看是誰建立了 Task,它的源頭在哪裡?可以用 ​

​!dso​

​ 檢視這個問題線程的所有棧對象。

0:069> !dumpstackobjects
OS Thread Id: 0x2d20 (69)
RSP/REG          Object           Name
r15              0000002031518d78 System.Threading.Thread
00000022C6EBE680 0000001db1a917a8 System.NullReferenceException
00000022C6EBE6A0 0000001db1a917a8 System.NullReferenceException
00000022C6EBE6F8 0000001db1a917a8 System.NullReferenceException
00000022C6EBE740 0000001db1a91c40 System.Threading.QueueUserWorkItemCallback
00000022C6EBE758 0000001db1a91ad0 System.Runtime.ExceptionServices.ExceptionDispatchInfo
00000022C6EBE760 0000001db1a917a8 System.NullReferenceException
00000022C6EBE780 0000002031518d78 System.Threading.Thread
00000022C6EBE788 0000001db1a91c40 System.Threading.QueueUserWorkItemCallback
00000022C6EBE790 0000001db1a917a8 System.NullReferenceException
00000022C6EBE7A8 0000001df1b95078 System.SByte[]
00000022C6EBE7B0 0000001df1392cc0 System.Threading.ContextCallback
00000022C6EBE7C0 0000001db1a917a8 System.NullReferenceException
00000022C6EBE880 0000001db1a91ad0 System.Runtime.ExceptionServices.ExceptionDispatchInfo
00000022C6EBE888 0000001db1a917a8 System.NullReferenceException
00000022C6EBE8A8 0000001db1a91c40 System.Threading.QueueUserWorkItemCallback
00000022C6EBE8B0 0000002031518d78 System.Threading.Thread
00000022C6EBE910 0000001df1392cc0 System.Threading.ContextCallback
00000022C6EBE920 0000001db1a917a8 System.NullReferenceException
00000022C6EBE928 0000001db1a91ad0 System.Runtime.ExceptionServices.ExceptionDispatchInfo
00000022C6EBE938 0000001db1a91cc8 System.Threading.ExecutionContext
00000022C6EBE940 0000001db1a91cc8 System.Threading.ExecutionContext
00000022C6EBE950 0000001df1392cc0 System.Threading.ContextCallback
00000022C6EBE990 0000002031518d78 System.Threading.Thread
00000022C6EBE9F0 0000001db1a91c40 System.Threading.QueueUserWorkItemCallback
00000022C6EBE9F8 0000001db1a91cc8 System.Threading.ExecutionContext
00000022C6EBEA60 0000001df1392c98 System.Threading.ThreadPoolWorkQueue
00000022C6EBEAB8 0000001fb114f2e8 System.Threading.TimerQueue
00000022C6EBEAD8 00000020314c0ae8 System.Threading.ThreadPoolWorkQueueThreadLocals
00000022C6EBEAE0 0000001df1392c98 System.Threading.ThreadPoolWorkQueue
00000022C6EBEB00 0000001db1a91c40 System.Threading.QueueUserWorkItemCallback
00000022C6EBEE18 0000001df19f8320 System.Web.Hosting.IIS7WorkerRequest


      

這裡有很多我們感興趣的對象,那源頭自然要深挖棧底對象 ​

​System.Web.Hosting.IIS7WorkerRequest​

​​ ,使用 ​

​!do xxx​

​ 指令。

使用 Windbg 分析一個 異步操作 引發的 Crash 異常

然後再挖裡面的 ​

​_path​

​​ 和 ​

​_httpVerb​

​​ 字段,繼續使用 ​

​!do​

​。

總結