WinDbg排查C#调用C++ DLL粘贴回调后随机崩溃根因
图片粘贴场景应用崩溃故障分析
故障背景
- 触发场景:执行图片粘贴操作时,程序调用C++编写的外部DLL实现相关逻辑;流程初始化阶段从C#侧注册回调函数,粘贴操作完成后触发C#侧回调逻辑,回调函数执行结束后应用直接崩溃,异常无法被任何try/catch块捕获
- 故障特征:随机偶现,无稳定复现路径,相关业务源代码超过2年未做任何变更
- 待确认问题:初步怀疑堆损坏导致崩溃,需确认故障属于堆泄漏还是堆越界异常,输出对应排查、处理方案
WinDbg崩溃转储原始输出
************* Path validation summary ************** Response Time (ms) Location Deferred srv* OK D:\Core\Bin Symbol search path is: srv*;D:\Core\Bin Executable search path is: Windows 10 Version 19044 MP (8 procs) Free x86 compatible Product: WinNt, suite: SingleUserTS Edition build lab: 19041.1.amd64fre.vb_release.191206-1406 Machine Name: Debug session time: Wed Jul 13 15:55:25.000 2022 (UTC + 5:30) System Uptime: 0 days 1:21:28.318 Process Uptime: 0 days 0:01:57.000 ................................................................ ................................................................ ................................................................ ................................................................ ................................................................ ................................................................ ................................................................ ................................................................ ................................................................ ..................... Loading unloaded module list ......... For analysis of this file, run !analyze -v eax=00000000 ebx=00c5e5e8 ecx=00000003 edx=00000000 esi=00000000 edi=000002f4 eip=778129fc esp=0019d0dc ebp=0019d14c iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 ntdll!NtWaitForSingleObject+0xc: 778129fc c20c00 ret 0Ch 0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* *** WARNING: Unable to verify checksum for libcef.dll *** WARNING: Unable to verify checksum for WindowsBase.ni.dll *** WARNING: Unable to verify checksum for PresentationCore.ni.dll *** WARNING: Unable to verify checksum for NextGen.Core.dll MethodDesc: 45b52128 Method Name: OnCallBackMethod(IntPtr, IntPtr, UInt32, ART_MARK_ATTRIBUTES, enumModifyReasons) Class: 45b690fc MethodTable: 45b52d70 mdToken: 06000242 Module: 1bcc94c4 IsJitted: yes CodeAddr: 09061a00 Transparency: Critical Source file: D:\Core\PasteImage.cs @ 724 MethodDesc: 476ed6a8 Method Name: DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int32, Int32, Int32, IntPtr, Int32) Class: 07d51b3c MethodTable: 07d51b90 mdToken: 06000000 Module: 00874044 IsJitted: yes CodeAddr: 47773910 Transparency: Safe critical Failed to request MethodData, not in JIT code range KEY_VALUES_STRING: 1 Key : Analysis.CPU.mSec Value: 67280 Key : Analysis.DebugAnalysisManager Value: Create Key : Analysis.Elapsed.mSec Value: 75763 Key : Analysis.Init.CPU.mSec Value: 4436 Key : Analysis.Init.Elapsed.mSec Value: 9321 Key : Analysis.Memory.CommitPeak.Mb Value: 228 Key : CLR.BuiltBy Value: NET48REL1LAST_C Key : CLR.Engine Value: CLR Key : CLR.Version Value: 4.8.4515.0 Key : Timeline.OS.Boot.DeltaSec Value: 4888 Key : Timeline.Process.Start.DeltaSec Value: 117 Key : WER.OS.Branch Value: vb_release Key : WER.OS.Timestamp Value: 2019-12-06T14:06:00Z Key : WER.OS.Version Value: 10.0.19041.1 Key : WER.Process.Version Value: 6.0.0.209 FILE_IN_CAB: CrashDump.dmp NTGLOBALFLAG: 0 PROCESS_BAM_CURRENT_THROTTLED: 0 PROCESS_BAM_PREVIOUS_THROTTLED: 0 APPLICATION_VERIFIER_FLAGS: 0 EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 00000000 ExceptionCode: 80000003 (Break instruction exception) ExceptionFlags: 00000000 NumberParameters: 0 FAULTING_THREAD: 00005474 PROCESS_NAME: NextGenEMR.exe ERROR_CODE: (NTSTATUS) 0x80000003 - {EXCEPTION} Breakpoint A breakpoint has been reached. EXCEPTION_CODE_STR: 80000003 IP_ON_HEAP: 477739d5 The fault address in not in any loaded module, please check your build's rebase log at <releasedir>\bin\build_logs\timebuild\ntrebase.log for module which may contain the address if it were loaded. FRAME_ONE_INVALID: 1 STACK_TEXT: 0019e0c8 09061cd1 OnCallBackMethod+0x2d1 0019e188 477739d5 unknown!unknown+0x0 0019e1ec 441b1553 unknown!unknown+0x0 0019e224 1c555afc igart18d+0x8e8c 0019e228 27195478 unknown!unknown+0x0 0019e240 27195478 unknown!unknown+0x0 0019e290 27195478 unknown!unknown+0x0 0019e2ac 1c5561d8 igart18d+0x9568 FAULTING_SOURCE_LINE: D:\Core\PasteImage.cs FAULTING_SOURCE_FILE: D:\Core\PasteImage.cs FAULTING_SOURCE_LINE_NUMBER: 724 SYMBOL_NAME: OnCallBackMethod+2d1 MODULE_NAME: ImagingControl IMAGE_NAME: ImagingControl.dll STACK_COMMAND: .cxr 19d618 ; kb ; ** Pseudo Context ** Pseudo ** Value: f8b83f0 ** ; kb FAILURE_BUCKET_ID: BREAKPOINT_80000003_OnCallBackMethod OS_VERSION: 10.0.19041.1 BUILDLAB_STR: vb_release OSPLATFORM_TYPE: x86 OSNAME: Windows 10 IMAGE_VERSION: 6.0.0.209 FAILURE_ID_HASH: {bd0e81c1-c531-0b4a-964b-28450da23c4b} Followup: MachineOwner --------- 0:000> k # ChildEBP RetAddr 00 0019d14c 75f82609 ntdll!NtWaitForSingleObject+0xc 01 0019d14c 729c1401 KERNELBASE!WaitForSingleObjectEx+0x99 02 0019d17c 729c145d clr!CLREventWaitHelper2+0x33 03 0019d1cc 729c13aa clr!CLREventWaitHelper+0x2a 04 0019d204 729c13cc clr!CLREventBase::WaitEx+0x14b 05 0019d21c 72c9e065 clr!CLREventBase::Wait+0x1a 06 0019d288 72c9e17a clr!Thread::WaitSuspendEventsHelper+0x8a 07 0019d29c 72c9c2aa clr!Thread::WaitSuspendEvents+0x14 08 0019d2b4 72a89aae clr!Thread::RareEnablePreemptiveGC+0x98 09 0019d2f8 72f642a5 clr!Thread::RareDisablePreemptiveGC+0x115 0a 0019d31c 72f69ccc clr!GCHolderEEInterface<0,1,1>::~GCHolderEEInterface<0,1,1>+0x61 0b 0019d38c 72f6a75b clr!DebuggerController::DispatchPatchOrSingleStep+0x1ef 0c 0019d3c0 72a7a625 clr!DebuggerController::DispatchNativeException+0x17c 0d 0019d3f0 72b4b82d clr!Debugger::FirstChanceNativeException+0x69 0e 0019d430 72b4b91e clr!CLRVectoredExceptionHandlerPhase2+0xa9 0f 0019d458 72b4d32c clr!CLRVectoredExceptionHandler+0xac 10 0019d498 72b4d47a clr!CPFH_FirstPassHandler+0x79 11 0019d4c4 77828a22 clr!COMPlusFrameHandler+0x15d 12 0019d4e8 778289f4 ntdll!ExecuteHandler2+0x26 13 0019d5b0 77814ee6 ntdll!ExecuteHandler+0x24 14 0019e170 09061cd1 ntdll!KiUserExceptionDispatcher+0x26 15 0019e170 477739d5 OnCallBackMethod+0x2d1 [PasteImage.cs @ 724] WARNING: Frame IP not in any known module. Following frames may be wrong. 16 0019e1e4 441b1553 0x477739d5 17 0019e21c 1c555afc 0x441b1553 18 27195478 27195478 igart18d!CPb_ART_done+0x8e8c 19 1c555afc 27195478 0x27195478 1a 0000000b 27195478 0x27195478 1b 1df00520 1c5561d8 0x27195478 1c 00000000 00000000 igart18d!CPb_ART_done+0x9568 0:000> dc 0x477739d5 477739d5 90909090 b9909090 46412a54 248baae8 ........T*AF...$ 477739e5 c045892b ffc0458d c8fde830 45892b3f +.E..E..0...?+.E 477739f5 b4558bb4 e80c4d8b 2b300d6f 000c7d83 ..U..M..o.0+.}.. 47773a05 7d8b1974 b9c0330c 00000029 006aabf3 t..}.3..).....j. 47773a15 8bac4d8b 80e80c55 c72b300c 0004d845 .M..U....0+.E... 47773a25 90904000 d845c790 7fffffff 00e845c7 .@....E......E.. 47773a35 c7000000 00fcec45 4f680000 eb47773a ....E.....hO:wG. 47773a45 f8658d12 c25d5f5e 45c7000c 000000ec ..e.^_]....E....
根因判定
该故障不属于堆泄漏,是典型的堆越界写导致的内存损坏。
- 堆泄漏的核心特征是进程内存占用持续增长,最终触发内存不足错误,不会随机在回调返回时触发断点、执行流跳转异常,和当前故障表现完全不符
- 转储中崩溃点
0x477739d5属于CLR动态生成的反向PInvoke调用桩内存区域(JIT生成的可执行代码存放在堆上的专属段),该区域内存被非法覆盖:起始位置连续写入了大量0x90(NOP空指令)和非预期代码,是越界写篡改可执行内存的直接证据 - 栈回溯出现大量无符号的未知栈帧、返回地址重复错乱,是栈内存、堆内存被越界写破坏的典型表现
- 崩溃发生在C#回调返回、CLR切换GC模式的阶段,此时执行流从托管代码返回非托管桩时,直接跳到了被篡改的内存地址触发断点异常,属于原生层内存错误,完全绕过C#托管异常捕获机制,因此try/catch无法捕获
排查方案
- 优先排查转储中出现的C++外部DLL
igart18d.dll的回调相关逻辑:- 检查C++侧回调函数指针的调用约定、参数列表,必须和C#侧委托声明完全匹配,参数个数、类型长度、调用约定(__stdcall/__cdecl)不一致会直接导致栈平衡错误,破坏栈内存
- 检查DLL内所有内存拷贝操作,重点排查无长度校验的
memcpy、strcpy类接口,确认不存在拷贝长度超出目标缓冲区分配大小的情况 - 检查DLL侧内存生命周期管理,确认不存在释放内存块后仍写入该内存地址的野指针问题
- 检查C#侧回调委托生命周期:传给非托管层的委托必须被持有强引用,若委托被GC回收后,C++侧仍保存对应函数指针发起调用,会直接跳转至已被释放、重新分配的JIT桩内存,触发执行流异常
- 开启堆监控工具定位越界点:
- 使用gflags工具为目标进程开启全页堆(
gflags /p /enable NextGenEMR.exe /full),复现崩溃时会直接在越界写操作的位置触发断点,不会等到内存被
- 使用gflags工具为目标进程开启全页堆(
相关产品推荐
相关产品推荐

