蛙蛙推荐:怎样调试asp.net黄页错
摘要:如果你的web应用莫名其妙的报了一个未处理异常,出现了一个黄色页面的错误,你都是如何来排错的?如果报错页面显示的调用栈上没有做任何log和trace,也没有对参数和全局变量做一些断言,你咋办?如果源码也不在你手上,你在给客户解决问题你咋办?
我们先来模拟问题,这是一个简单的页面,接受一个查询字符串,如果这个字符串能转换成整形,并且是偶数,就原样输出,如果是奇数,Page_Load方法里没有进行对handleInput方法的返回值进行是否为空的判断就直接调用ToUper的方法,所以当查询字符串为奇数的时候就会抛出未处理异常,出现大黄页,代码如下
using System;
using System.Web.UI;
namespace WebApplication1
{
public partial class TestException : Page
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
string input = Request.QueryString["id"];
//这里没有判断handleInput方法的返回值
Response.Write(handleInput(input).ToUpper());
}
catch (ArgumentNullException ane)
{
Response.Write(ane.Message);
Response.End();
}
catch (ArgumentException ae)
{
Response.Write(ae.Message);
Response.End();
}
}
private static string handleInput(string input)
{
if (string.IsNullOrEmpty(input))
throw new ArgumentNullException("input", "输入数据不能为空");
int intInput;
if (!int.TryParse(input, out intInput))
throw new ArgumentException("输入数据不是整形", "input");
return intInput %2 == 0 ? intInput.ToString() : null;
//这里没有检查后置参数的值,导致该方法可返回无效值null。
}
}
}
有时候我们机器上有多个网站,每个网站使用不同的应用程序池,这就会有多个w3wp进程,我们得先确定我们的web应用的进程ID,用以下命令找出,我的机器就一个应用程序池,是1592,打开windbg,按f6附加进程
C:\Documents and Settings\Administrator>iisapp
W3WP.exe PID: 1592 AppPoolId: ASP.NET V2.0
然后按顺序来排查
1、加载SOS
.loadby sos mscorwks
2、找出空引用异常的方法表地址
!name2ee *!System.NullReferenceException
0:026> !name2ee *!System.NullReferenceException
*********************************************************************
* Symbols can not be loaded because symbol path is not initialized. *
* *
* The Symbol Path can be set by: *
* using the _NT_SYMBOL_PATH environment variable. *
* using the -y <symbol_path> argument when starting the debugger. *
* using .sympath and .sympath+ *
*********************************************************************
PDB symbol for mscorwks.dll not loaded
Module: 106f1000 (System.WorkflowServices.dll)
--------------------------------------
Module: 65ce1000 (System.Web.Services.dll)
--------------------------------------
Module: 027f1000 (SMDiagnostics.dll)
--------------------------------------
Module: 10ec1000 (System.Runtime.Serialization.dll)
--------------------------------------
Module: 64891000 (System.Configuration.dll)
--------------------------------------
Module: 65f21000 (System.Web.dll)
--------------------------------------
Module: 7a441000 (System.dll)
--------------------------------------
Module: 021e2698 (CppCodeProvider.dll)
--------------------------------------
Module: 02921000 (System.EnterpriseServices.dll)
--------------------------------------
Module: 10a11000 (System.EnterpriseServices.Wrapper.dll)
--------------------------------------
Module: 790c1000 (mscorlib.dll)
Token: 0x020000dc
MethodTable: 7931fec0
EEClass: 7914e0d0
Name: System.NullReferenceException
--------------------------------------
Module: 021e2354 (sortkey.nlp)
--------------------------------------
Module: 021e2010 (sorttbls.nlp)
--------------------------------------
Module: 021e2c04 (prcp.nlp)
--------------------------------------
Module: 695a1000 (System.Web.Mobile.dll)
--------------------------------------
Module: 021e329c (mscorlib.resources.dll)
--------------------------------------
Module: 637a1000 (System.Xml.dll)
--------------------------------------
Module: 0ea31000 (System.ServiceModel.dll)
--------------------------------------
Module: 65151000 (System.Data.dll)
--------------------------------------
Module: 5e621000 (Microsoft.JScript.dll)
--------------------------------------
Module: 021e35f0 (System.Web.resources.dll)
--------------------------------------
Module: 6c3b1000 (VJSharpCodeProvider.dll)
--------------------------------------
Module: 7ade1000 (System.Drawing.dll)
--------------------------------------
Module: 66f01000 (System.Web.RegularExpressions.dll)
--------------------------------------
Module: 100c1000 (System.ServiceModel.Web.dll)
--------------------------------------
Module: 10ba1000 (System.IdentityModel.dll)
--------------------------------------
Module: 021e2f48 (System.resources.dll)
--------------------------------------
Module: 02638280 ()
--------------------------------------
Module: 026393b4 ()
--------------------------------------
Module: 02639734 ()
--------------------------------------
Module: 10d10010 ()
--------------------------------------
Module: 026c82d4 (WebApplication1.DLL)
--------------------------------------
Module: 026c9180 ()
--------------------------------------
Module: 026c9500 ()
--------------------------------------
Module: 026c9b3c (App_Web_qt-srzwh.dll)
3、找出空引用方法表的方法描述
!dumpmt -md 7931fec0
0:026> !dumpmt -md 7931fec0
EEClass: 7914e0d0
Module: 790c1000
Name: System.NullReferenceException
mdToken: 020000dc (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
BaseSize: 0x48
ComponentSize: 0x0
Number of IFaces in IFaceMap: 2
Slots in VTable: 21
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
79240bc8 79106234 PreJIT System.Exception.ToString()
79286a90 7910493c PreJIT System.Object.Equals(System.Object)
79286b00 7910496c PreJIT System.Object.GetHashCode()
792f72f0 79104990 PreJIT System.Object.Finalize()
79240bd8 7910617c PreJIT System.Exception.get_Message()
792993f0 7910618c PreJIT System.Exception.get_Data()
79744d94 791061c0 PreJIT System.Exception.GetBaseException()
792995d0 791061c8 PreJIT System.Exception.get_InnerException()
79745530 791061ec PreJIT System.Exception.get_TargetSite()
792994f0 79106200 PreJIT System.Exception.get_StackTrace()
79745460 79106214 PreJIT System.Exception.get_HelpLink()
79745440 7910621c PreJIT System.Exception.set_HelpLink(System.String)
797453a4 79106224 PreJIT System.Exception.get_Source()
79745390 7910622c PreJIT System.Exception.set_Source(System.String)
79255968 79106264 PreJIT System.Exception.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)
79744b44 791062b4 PreJIT System.Exception.InternalToString()
79744b30 791062bc PreJIT System.Exception.GetType()
79253fc0 7919b748 PreJIT System.NullReferenceException..ctor()
797d15ec 7919b758 PreJIT System.NullReferenceException..ctor(System.String)
797d15c4 7919b764 PreJIT System.NullReferenceException..ctor(System.String, System.Exception)
797d1610 7919b770 PreJIT System.NullReferenceException..ctor(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)
4、在空引用异常对象的构造函数上设置断点
!bpmd -md 7919b748
0:026> !bpmd -md 7919b748
MethodDesc = 7919b748
Setting breakpoint: bp 797D158C [System.NullReferenceException..ctor()]
*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\9adb89fa22fd5b4ce433b5aca7fb1b07\mscorlib.ni.dll
*** ERROR: Module load completed but symbols could not be loaded for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\9adb89fa22fd5b4ce433b5aca7fb1b07\mscorlib.ni.dll
5、继续执行程序并测试程序
0:026> g
(638.bc8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=02b920c4 ecx=00000000 edx=00000000 esi=06b23cec edi=02b920c4
eip=1166064f esp=1138f260 ebp=1138f2cc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
WebApplication1!WebApplication1.TestException.Page_Load(System.Object, System.EventArgs)+0x8f:
1166064f 3909 cmp dword ptr [ecx],ecx ds:0023:00000000=????????
*** WARNING: Unable to verify checksum for C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\webapplication1\c72f0972\f7fe4744\assembly\dl3\ab709657\703b76b7_0218c901\WebApplication1.DLL
6、查看调用栈及调用栈的参数和临时变量
0:022> !clratack -a
No export clratack found
0:022> !clrstack -a
OS Thread Id: 0xbc8 (22)
ESP EIP
1138f260 1166064f WebApplication1.TestException.Page_Load(System.Object, System.EventArgs)
PARAMETERS:
this = 0x06b235c4
sender = 0x06b235c4
e = 0x02b920c4
LOCALS:
0x1138f2a0 = 0x06b243d4
0x1138f29c = 0x00000000
0x1138f298 = 0x00000000
1138f2d8 66f2a7ff System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
PARAMETERS:
fp = <no data>
o = <no data>
t = <no data>
e = <no data>
1138f2e8 660b2344 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
PARAMETERS:
this = <no data>
sender = <no data>
e = <no data>
1138f2fc 660ab864 System.Web.UI.Control.OnLoad(System.EventArgs)
PARAMETERS:
this = <no data>
e = <no data>
LOCALS:
<no data>
1138f310 660ab8a3 System.Web.UI.Control.LoadRecursive()
PARAMETERS:
this = 0x06b235c4
LOCALS:
<no data>
<no data>
<no data>
1138f328 660a7954 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
PARAMETERS:
this = 0x06b235c4
includeStagesBeforeAsyncPoint = 0x00000001
includeStagesAfterAsyncPoint = 0x00000001
LOCALS:
0x1138f334 = 0x06b21d04
0x1138f330 = 0x00000000
0x1138f32c = 0x02a301d0
<no data>
<no data>
<no data>
<no data>
<no data>
1138f480 660a7584 System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
PARAMETERS:
this = 0x06b235c4
includeStagesBeforeAsyncPoint = <no data>
includeStagesAfterAsyncPoint = 0x00000001
LOCALS:
0x1138f484 = 0x00000000
1138f4b8 660a74b1 System.Web.UI.Page.ProcessRequest()
PARAMETERS:
this = 0x06b235c4
LOCALS:
0x1138f4c0 = 0x02a9e97c
0x1138f4bc = 0x06a87bcc
0x1138f4b8 = 0x06a87bcc
1138f4f0 660a7446 System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)
PARAMETERS:
this = <no data>
context = <no data>
1138f4fc 660a7422 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
PARAMETERS:
this = <no data>
context = <no data>
1138f510 1166025e ASP.testexception_aspx.ProcessRequest(System.Web.HttpContext)
PARAMETERS:
this = 0x06b235c4
context = 0x06b21d04
1138f520 660ad8f6 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
PARAMETERS:
this = <no data>
LOCALS:
0x1138f528 = 0x06b21d04
<no data>
<no data>
<no data>
<no data>
<no data>
1138f554 6608132c System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
PARAMETERS:
this = 0x02b79ab0
step = 0x02b8fb6c
completedSynchronously = 0x1138f5b0
LOCALS:
0x1138f55c = 0x00000000
<no data>
<no data>
<no data>
<no data>
1138f594 6608c3a3 System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)
PARAMETERS:
this = 0x02b8c614
error = <no data>
LOCALS:
0x1138f5b4 = 0x00000000
0x1138f5b0 = 0x00000001
0x1138f5a4 = 0x02b79ab0
0x1138f5a0 = 0x06b21d04
0x1138f59c = 0x06b22034
0x1138f598 = 0x06b22014
<no data>
0x1138f594 = 0x02b79ab0
1138f5e4 660808ac System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
PARAMETERS:
this = <no data>
context = <no data>
cb = <no data>
extraData = <no data>
LOCALS:
<no data>
1138f600 66083e1c System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
PARAMETERS:
this = 0x02aa1354
wr = 0x06b21418
LOCALS:
0x1138f600 = 0x06b21d04
<no data>
<no data>
<no data>
<no data>
1138f634 66083ac3 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)
PARAMETERS:
wr = <no data>
LOCALS:
<no data>
1138f644 66082c5c System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
PARAMETERS:
this = 0x02b5e0e4
ecb = <no data>
iWRType = <no data>
LOCALS:
0x1138f688 = 0x01fe3d08
0x1138f67c = 0x06b21418
<no data>
<no data>
<no data>
<no data>
<no data>
<no data>
1138f858 79f68c4e [ContextTransitionFrame: 1138f858]
1138f88c 79f68c4e [GCFrame: 1138f88c]
1138f9e8 79f68c4e [ComMethodFrame: 1138f9e8]
6、分析调用栈的参数和临时变量,从上面看到TestException.Page_Load有3个临时变量,其中后两个是空引用,虽然看不到这三个临时变量的变量名(不可能能看到),但根据代码可以推断出后面两个参数其中之一是handleResult的返回值,所以问题就在这儿。我们可以打印出第一个参数来看这个参数是不是我们所期望的,结果打印出来的值是个奇数,问题就确认了,到时候再来看客户为什么输入奇数就行了。
0:022> !do 0x06b243d4
Name: System.String
MethodTable: 793308ec
EEClass: 790ed64c
Size: 20(0x14) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: 1
Fields:
MT Field Offset Type VT Attr Value Name
79332b38 4000096 4 System.Int32 1 instance 2 m_arrayLength
79332b38 4000097 8 System.Int32 1 instance 1 m_stringLength
793315cc 4000098 c System.Char 1 instance 31 m_firstChar
793308ec 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000ce120:02a301d0 000fc948:02a301d0 0017ac48:02a301d0 <<
7933151c 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000ce120:02a30728 000fc948:06a30bd4 0017ac48:06a87b80 <<
7、保存转储文件
.dump /f /o c:\temp.dmp
后续:如果只为了捕获异常,可以设置windbg的配置文件来让出现某些异常的时候自动调试,还可以用gflag或者手工修改注册表让某个应用崩溃的时候自动抓取Dump,本文是另一种思路,用设置断点的方式来排查问题。
关于windbg的使用,可以参考如下链接
或者熊力的《windows用户态程序高效排错》