找回密码
 立即注册
首页 业界区 业界 记一次 .NET 某企业审批系统 崩溃分析

记一次 .NET 某企业审批系统 崩溃分析

印萍 8 小时前
一:背景

1. 讲故事

今年年初有位朋友在微信上找到我,说他们的系统在客户这边崩掉了,在代码中也加了全局异常处理但还是崩,不知道咋回事,让朋友在客户那边拿程序dump,拿到dump之后开始分析。
二:崩溃分析

1. 为什么会崩溃

既然是崩溃,那就用 !analyze -v 命令观察下windbg给我们整理的崩溃信息,看看可有蛛丝马迹。
  1. 0:000> !analyze -v
  2. *******************************************************************************
  3. *                                                                             *
  4. *                        Exception Analysis                                   *
  5. *                                                                             *
  6. *******************************************************************************
  7. CONTEXT:  (.ecxr)
  8. eax=006fdb40 ebx=00000005 ecx=00000005 edx=00000000 esi=006fdc04 edi=00000001
  9. eip=768f9132 esp=006fdb40 ebp=006fdb9c iopl=0         nv up ei pl nz ac po nc
  10. cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
  11. KERNELBASE!RaiseException+0x62:
  12. 768f9132 8b4c2454        mov     ecx,dword ptr [esp+54h] ss:002b:006fdb94=005b1570
  13. Resetting default scope
  14. EXCEPTION_RECORD:  (.exr -1)
  15. ExceptionAddress: 768f9132 (KERNELBASE!RaiseException+0x00000062)
  16.    ExceptionCode: e0434352 (CLR exception)
  17.   ExceptionFlags: 00000001
  18. NumberParameters: 5
  19.    Parameter[0]: 80131604
  20.    Parameter[1]: 00000000
  21.    Parameter[2]: 00000000
  22.    Parameter[3]: 00000000
  23.    Parameter[4]: 72e90000
  24. PROCESS_NAME:  xxx.exe
  25. EXCEPTION_CODE_STR:  8007000e
  26. FAULTING_THREAD:  ffffffff
  27. STACK_TEXT:  
  28. 006fde30 07a0941c System_Drawing!System.Drawing.Graphics.FromHdcInternal+0x4c
  29. 006fde40 1173bbdb System_Drawing!System.Drawing.Font.GetHeight+0x5b
  30. 006fde70 1173bb4b System_Drawing!System.Drawing.Font.get_Height+0xb
  31. 006fde80 178658d4 DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.CalcSizes+0x304
  32. 006fdf4c 17864f4f DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.OnPaint+0x9f
  33. 006fe0b0 0705ab89 System_Windows_Forms!System.Windows.Forms.Control.PaintWithErrorHandling+0x89
  34. 006fe0e0 07058d75 System_Windows_Forms!System.Windows.Forms.Control.WmPaint+0x47d
  35. 006fe1d8 07a003db System_Windows_Forms!System.Windows.Forms.Control.WndProc+0x39b
  36. 006fe218 0707f821 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.OnMessage+0x11
  37. 006fe220 0707f7f8 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.WndProc+0xa0
  38. 006fe234 0707f227 System_Windows_Forms!System.Windows.Forms.NativeWindow.Callback+0x5f
复制代码
从卦中可以看到 ExceptionCode: e0434352,这很明显是一个 托管异常,既然是 托管异常 那为什么朋友的代码拦截不到呢?这就比较有意思了,那到底是什么类型的托管异常,用 !t 观察一下。
  1. 0:000> !t
  2. ThreadCount:      13
  3. UnstartedThread:  0
  4. BackgroundThread: 11
  5. PendingThread:    0
  6. DeadThread:       1
  7. Hosted Runtime:   no
  8.                                                                          Lock  
  9.        ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
  10.    0    1 68b4 00970248     26020 Preemptive  2BB06608:00000000 0096ad08 1     STA System.Reflection.TargetInvocationException 2baf5884 (nested exceptions)
  11.    2    2 8b90 0098a220     2b220 Preemptive  00000000:00000000 0096ad08 0     MTA (Finalizer)
  12.    5    4  1cc 05e3f308   202b220 Preemptive  00000000:00000000 0096ad08 0     MTA
  13.    ...
复制代码
从卦中的 System.Reflection.TargetInvocationException 可以看到这是一个 调用目标异常,由于卦象上有 (nested exceptions) 标记,使用 !pe -nested  命令观察异常链走势。
  1. 0:000> !pe -nested
  2. Exception object: 2baf5884
  3. Exception type:   System.Reflection.TargetInvocationException
  4. Message:          调用的目标发生了异常。
  5. InnerException:   System.ComponentModel.Win32Exception, Use !PrintException 96e70c07 to see more.
  6. StackTrace (generated):
  7.     SP       IP       Function
  8.     00000000 00000001 mscorlib_ni!System.RuntimeMethodHandle.SerializationInvoke(System.IRuntimeMethodInfo, System.Object, System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext ByRef)+0xffffffff8d074f41
  9.     xxx
  10.     006FDFF4 71891968 mscorlib_ni!System.Resources.RuntimeResourceSet.GetObject(System.String, Boolean, Boolean)+0x1e8
  11.     006FE074 7189B263 mscorlib_ni!System.Resources.RuntimeResourceSet.GetObject(System.String, Boolean)+0x13
  12.     006FE07C 7189331B mscorlib_ni!System.Resources.ResourceManager.GetObject(System.String, System.Globalization.CultureInfo, Boolean)+0x22b
  13.     006FE0DC 7194FD5B mscorlib_ni!System.Resources.ResourceManager.GetObject(System.String)+0xf
  14.     006FE0E0 07CB92F8 xxx.frmBase.InitializeComponent()+0x68
  15.     006FE0F0 0707308A xxx.frmBase..ctor()+0x42
  16.     006FE100 05202B3D xxx.frmErrorMessage..ctor()+0xd
  17.     006FE10C 05202A03 xxx.ExceptionHandler.HandlerErr(System.Exception)+0x23
  18.     006FE11C 052029C9 xxx.UnhandledExceptionManager.Application_ThreadException(System.Object, System.Threading.ThreadExceptionEventArgs)+0x9
  19.     006FE120 052027E8 System_Windows_Forms!System.Windows.Forms.Application+ThreadContext.OnThreadException(System.Exception)+0x88
  20.     006FE15C 05202746 System_Windows_Forms!System.Windows.Forms.Control.WndProcException(System.Exception)+0x16
  21.     006FE168 0520271A System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.OnThreadException(System.Exception)+0xa
  22.     006FE16C 0707F256 System_Windows_Forms!System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)+0x8e
  23. StackTraceString: <none>
  24. HResult: 80131604
  25. Nested exception -------------------------------------------------------------
  26. Exception object: 2baeb3b0
  27. Exception type:   System.OutOfMemoryException
  28. Message:          内存不足。
  29. InnerException:   <none>
  30. StackTrace (generated):
  31.     SP       IP       Function
  32.     006FDE30 07A0941C System_Drawing!System.Drawing.Graphics.FromHdcInternal(IntPtr)+0x4c
  33.     006FDE40 1173BBDB System_Drawing!System.Drawing.Font.GetHeight()+0x5b
  34.     006FDE70 1173BB4B System_Drawing!System.Drawing.Font.get_Height()+0xb
  35.     006FDE80 178658D4 DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.CalcSizes(System.Drawing.Graphics)+0x304
  36.     006FDF4C 17864F4F DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.OnPaint(System.Windows.Forms.PaintEventArgs)+0x9f
  37.     006FE0B0 0705AB89 System_Windows_Forms!System.Windows.Forms.Control.PaintWithErrorHandling(System.Windows.Forms.PaintEventArgs, Int16)+0x89
  38.     006FE0E0 07058D75 System_Windows_Forms!System.Windows.Forms.Control.WmPaint(System.Windows.Forms.Message ByRef)+0x47d
  39.     006FE1D8 07A003DB System_Windows_Forms!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)+0x39b
  40.     006FE218 0707F821 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)+0x11
  41.     006FE220 0707F7F8 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)+0xa0
  42.     006FE234 0707F227 System_Windows_Forms!System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)+0x5f
  43. StackTraceString: <none>
  44. HResult: 8007000e
复制代码
从卦象看,程序是先抛出了 OutOfMemoryException 异常,在全局异常处理中再次抛出 TargetInvocationException 引发程序崩溃,接下来看下为什么会抛 OutOfMemoryException 异常呢?导出源代码观察,简化后如下:
  1. public float GetHeight()
  2. {
  3.     IntPtr dC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
  4.     float num = 0f;
  5.     try
  6.     {
  7.         using Graphics graphics = Graphics.FromHdcInternal(dC);
  8.         return GetHeight(graphics);
  9.     }
  10.     finally
  11.     {
  12.         UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dC));
  13.     }
  14. }
  15. public static Graphics FromHdcInternal(IntPtr hdc)
  16. {
  17.     IntPtr graphics = IntPtr.Zero;
  18.     int num = SafeNativeMethods.Gdip.GdipCreateFromHDC(new HandleRef(null, hdc), out graphics);
  19.     if (num != 0)
  20.     {
  21.         throw SafeNativeMethods.Gdip.StatusException(num);
  22.     }
  23.     return new Graphics(graphics);
  24. }
  25. internal static Exception StatusException(int status)
  26. {
  27.     return status switch
  28.     {
  29.         2 => new ArgumentException(SR.GetString("GdiplusInvalidParameter")),
  30.         3 => new OutOfMemoryException(SR.GetString("GdiplusOutOfMemory")),
  31.         ...
  32.     };
  33. }
复制代码
从卦象看,应该就是 GdipCreateFromHDC 方法返回 num=3,继而代码上手工 throw OutOfMemoryException,这里不是引发程序崩溃的直接原因,所以暂时就不深究了,转头关注核心的 HandlerErr 方法。
2. 全局异常处理崩溃探究

接下来回头看为什么 Application_ThreadException -> HandlerErr 全局异常处理中会再次抛异常?观察源代码发现是在初始化 frmErrorMessage 的时候抛错的。。。无语了。。。难怪拦截不到,截图如下:
1.png

细心的朋友会发现上面还有一句话 System.ComponentModel.Win32Exception, Use !PrintException 96e70c07 to see more.,即 TargetInvocationException 的内部还有一个异常 Win32Exception,可以用 !pe 显示出来。
  1. 0:000> !PrintException /d 2baf5360
  2. Exception object: 2baf5360
  3. Exception type:   System.ComponentModel.Win32Exception
  4. Message:          操作成功完成。
  5. InnerException:   <none>
  6. StackTrace (generated):
  7.     SP       IP       Function
  8.     006FDA9C 07CBA3BA System_Drawing!System.Drawing.Icon.Initialize(Int32, Int32)+0x83a
  9.     006FDB6C 07CB9B49 System_Drawing!System.Drawing.Icon..ctor(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)+0xc1
  10. StackTraceString: <none>
  11. HResult: 80004005
  12. There are nested exceptions on this thread. Run with -nested for details
复制代码
到这里逻辑基本就搞清楚了。

  • 业务代码在 System.Drawing.Graphics.FromHdcInternal 处抛了一个 OutOfMemoryException 进入全局异常拦截。
  • 在全局异常拦截中,又不幸在 new frmErrorMessage() 下 System.Drawing.Icon.Initialize 处抛出了 Win32Exception 异常。
最后就是 Icon.Initialize 函数为什么会抛异常?说实话我也搞不清楚,在 stackoverflow  https://stackoverflow.com/questions/2356580/system-drawing-icon-constructor-throwing-operation-completed-successfully-exce 上找到了这样的解读,截图如下:
2.png

最后给到朋友的建议:

  • 设置多尺寸的 icon 图片,再观察效果。
  • 修改 frmErrorMessage,避免双异常。
三:总结

本次事故是 多异常的联合作战 成功在高压的全局异常拦截方法Application_ThreadException中逃逸,是不是非常的有意思,示警大家,警惕被偷家!
3.jpeg

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册