原文地址:http://blogs.msdn.com/b/tess/archive/2008/03/05/net-debugging-demos-lab-5-crash.aspx
操作步骤:
1、运行CompanyInformation.aspx
2、在输入框中输入一个字符串,如aaa,点Send按钮
3、等了几秒钟,IE报错:无法显示网页
4、抓一个crash的dump,加载SOS,看一下!threads,输出如下:
Hosted Runtime: yes
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
XXXX 1 dd0 000dbce8 1808220 Disabled 00000000:00000000 00102870 1 Ukn (Threadpool Worker) System.StackOverflowException (0291106c) (nested exceptions)
XXXX 2 f70 000e7ec8 b220 Enabled 00000000:00000000 000d91a0 0 Ukn (Finalizer)
XXXX 3 f80 000ec3a8 1220 Enabled 00000000:00000000 000d91a0 0 Ukn
XXXX 4 868 000ff360 80a220 Enabled 00000000:00000000 000d91a0 0 Ukn (Threadpool Completion Port)
XXXX 5 fac 00151ad0 880a220 Enabled 00000000:00000000 000d91a0 0 Ukn (Threadpool Completion Port)
托管线程有5个,但是都挂掉了。
5、重新抓dump,使用参数-FullOnFirst,等了N久,dump也没抓完。咋回事?停掉adplus,到dump目录看一下,2分钟内,居然有10几个dump,而且大小完全一致。
6、打开最早的一个dump,由于是crash的dump,所以windbg自动切换到出问题的线程,如下:
OS Thread Id: 0x364 (16)
ESP EIP
0203f1f0 7c80bee7 [HelperMethodFrame: 0203f1f0]
0203f294 05770ae7 BuggyMail.IsValidEmailAddress(System.String)
嗯,看来是IsValidEmailAddress这里出问题了。
7、别急,打开第二个dump看看:
OS Thread Id: 0x364 (16)
ESP EIP
0203efbc 7c80bee7 [HelperMethodFrame: 0203efbc]
0203f060 7948d980 System.IO.__Error.WinIOError(Int32, System.String)
0203f08c 79395557 System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean)
0203f184 793983c8 System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.FileOptions)
0203f1b0 793984e3 System.IO.StreamWriter.CreateFile(System.String, Boolean)
0203f1c0 79398550 System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding, Int32)
0203f1e0 7949959c System.IO.StreamWriter..ctor(System.String)
0203f1ec 05770b52 Utility.WriteToLog(System.String, System.String)
0203f220 05770b0b ExceptionHandler.LogException(System.Exception)
0203f224 05770a81 BuggyMail.SendEmail(System.String, System.String)
比较有意思,在SendEmail里面,调用了LogException,然后在最上面产生了一个WinIOError
8、打开最后一个看看:
OS Thread Id: 0x364 (16)
ESP EIP
0203ec4c 7c80bee7 [HelperMethodFrame: 0203ec4c]
0203ecf0 7948d980 System.IO.__Error.WinIOError(Int32, System.String)
0203ed1c 79395557 System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean)
0203ee14 793983c8 System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.FileOptions)
0203ee40 793984e3 System.IO.StreamWriter.CreateFile(System.String, Boolean)
0203ee50 79398550 System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding, Int32)
0203ee70 7949959c System.IO.StreamWriter..ctor(System.String)
0203ee7c 05770b52 Utility.WriteToLog(System.String, System.String)
0203eeb0 05770b0b ExceptionHandler.LogException(System.Exception)
0203eeb4 05770bd4 Utility.WriteToLog(System.String, System.String)
0203ef60 05770b0b ExceptionHandler.LogException(System.Exception)
0203ef64 05770bd4 Utility.WriteToLog(System.String, System.String)
0203f010 05770b0b ExceptionHandler.LogException(System.Exception)
0203f014 05770bd4 Utility.WriteToLog(System.String, System.String)
0203f0c0 05770b0b ExceptionHandler.LogException(System.Exception)
0203f0c4 05770bd4 Utility.WriteToLog(System.String, System.String)
0203f170 05770b0b ExceptionHandler.LogException(System.Exception)
0203f174 05770bd4 Utility.WriteToLog(System.String, System.String)
0203f220 05770b0b ExceptionHandler.LogException(System.Exception)
0203f224 05770a81 BuggyMail.SendEmail(System.String, System.String)
0203f2c8 05770a28 CompanyInformation.btnContact_Click(System.Object, System.EventArgs)
从最下面的SendEmail往上看,LogException调用了WriteToLog,然后WriteToLog又调用了LogException,后者又调用了WriteToLog。
9、结合上面步骤4的线程1最后那个列:StackOverFlowException,我们猜测,上面步骤8的结果可能就是StackOverFlowException的原因。那么,步骤8的最上面一行的WinIOError是什么意思呢?我们看一下出问题的线程16上的栈上的变量,运行!dso,结果如下:(部分)
0203ee48 02b38358 System.String c:\log.txt
0203ee54 02b3a850 System.String Access to the path 'c:\log.txt' is denied.
10、基本能猜测到,要访问c:\log.txt,但是无权限导致IOError的。
11、看代码,找到SendEmail那段:
public void SendEmail(string message, string emailAddres){
try
{
if (IsValidEmailAddress(emailAddres))
{
// send an email with the message
}
}
catch (Exception ex)
{
ExceptionHandler.LogException(ex);
}
}
回到步骤6,正是从IsValidEmailAddress开始发生异常的。由于我输入的字符串是bbb,不是一个合理的email地址,所以会有异常(可以看Isvalid这个方法),然后异常被扔到了catch块中。
12、看catch里面的LogException怎么写的:
public static void LogException(Exception ex)
{
Utility.WriteToLog(ex.Message, "c:\\log.txt");
}
13、哈,这里出现了上面从!dso中看到的c:\log.txt字符串。这个没问题,看WriteToLog怎么写的。代码如下:
public static void WriteToLog(string message, string fileName)
{
try
{
using (StreamWriter sw = new StreamWriter(fileName))
{
//Log the event with date and time.
sw.WriteLine("--------------------------");
sw.WriteLine(DateTime.Now.ToLongTimeString());
sw.WriteLine("-------------------");
sw.WriteLine(message);
}
}
catch (Exception ex)
{
ExceptionHandler.LogException(ex);
}
}
这里try的地方可能会有问题,比如无权限、文件不存在等。关键的地方在于,try的地方如果出错,会被扔到catch块里面,执行LogException操作。
看明白了吗?如果这里有exception出现,就又返回到了步骤12中,最终又调用到了这里,又有exception,又返回到步骤12………………
14、解决办法,手工创建一个c:\log.txt,右键修改该文件的security,增加iuser_机器名这个用户,赋予full control。重新运行程序,好了。
Over