Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 6개 있습니다.)
디버깅 기술: 58. windbg 분석 사례 - WPF 응용 프로그램의 UI가 반응하지 않는 문제
; https://www.sysnet.pe.kr/2/0/1528

디버깅 기술: 63. windbg 디버깅 사례: AppDomain 간의 static 변수 사용으로 인한 crash
; https://www.sysnet.pe.kr/2/0/1616

디버깅 기술: 78. windbg 사례 - .NET 예외가 발생한 시점의 오류 분석
; https://www.sysnet.pe.kr/2/0/10942

디버깅 기술: 108. windbg 분석 사례 - Redis 서버로의 호출을 기다리면서 hang 현상 발생
; https://www.sysnet.pe.kr/2/0/11350

디버깅 기술: 167. windbg 디버깅 사례: AppDomain 간의 static 변수 사용으로 인한 crash (2)
; https://www.sysnet.pe.kr/2/0/12282

디버깅 기술: 174. windbg - System.TypeLoadException 예외 분석 사례
; https://www.sysnet.pe.kr/2/0/12410




windbg 사례 - .NET 예외가 발생한 시점의 오류 분석

이상하게 특정 상황에서 System.TypeInitializationException 예외가 발생하는 현상이 나왔습니다. 다행히 항상 발생해서 다음과 같이 프로세스 덤프를 떠 상황을 살펴봤습니다.

procdump -ma  -e 1 -f TypeInit* [...process id...]

windbg에서 덤프 파일을 로드하고 sos 확장을 올린 후,

0:085> .load C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\sos.dll

System.TypeInitializationException 예외가 발생한 스레드를 찾아,

0:085> !threads
DBGHELP: mscorwks - public symbols  
         d:\symbols\mscorwks.pdb\39E8C83B21A943B2B2DBC56A5E85676A1\mscorwks.pdb
ThreadCount: 64
UnstartedThread: 0
BackgroundThread: 64
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
                                              PreEmptive                                                Lock
       ID OSID        ThreadOBJ     State   GC     GC Alloc Context                  Domain           Count APT Exception
  14    1  3c4 00000000036a8580   1808228 Enabled  00000000c06ae3a0:00000000c06af788 0000000000128a60     0 MTA (Threadpool Worker)
  18    2 15cc 00000000036b13a0      b228 Enabled  0000000080436ec8:0000000080437110 0000000000128a60     0 MTA (Finalizer)
  19    3 197c 00000000047822b0    80a228 Enabled  0000000000000000:0000000000000000 0000000000128a60     0 MTA (Threadpool Completion Port)
...[생략]...
  85   43  c34 000000000b326010   188b228 Enabled  0000000080851f98:0000000080853338 000000000493cc00     1 MTA (Threadpool Worker) System.TypeInitializationException (00000000c039d708)
  86   56 1230 000000000a54d010   880b228 Enabled  0000000080478468:0000000080479220 0000000000128a60     0 MTA (Threadpool Completion Port)
...[생략]...

대상 스레드로 문맥 전환을 하고,

0:085> ~85s

예외를 조사했습니다.

0:085> !pe
Exception object: 00000000c039d708
Exception type: System.TypeInitializationException
Message: The type initializer for 'TestLib.MyTestClass' threw an exception.
InnerException: System.AccessViolationException, use !PrintException 00000000c039d4e8 to see more
StackTrace (generated):
    SP               IP               Function
    000000000946DFA0 0000000000000001 TestWebSite!TestLib.MyTestClass..ctor()+0x2
    000000000946E070 0000064281C70533 TestWebSite!TestLib.TempWebPage.Page_Load(System.Object, System.EventArgs)+0x63

StackTraceString: <none>
HResult: 80131534

친절하게 InnerException을 살펴보라고 하는데,

0:085> !PrintException 00000000c039d4e8
Exception object: 00000000c039d4e8
Exception type: System.AccessViolationException
Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
InnerException: <none>
StackTrace (generated):
    SP               IP               Function
    000000000F25CAE0 0000000000000001 TestWebSite!TestLib.MyTestClass..cctor()+0x2

StackTraceString: <none>
HResult: 80004003

딱히 정보가 없습니다. 혹시나 해서 대상 메서드를 좀 더 조사해봤지만,

0:085> !name2ee TestWebSite!TestLib.MyTestClass..cctor
Module: 00000642803f6008 (TestWebSite.DLL)
Token: 0x0000000006000360
MethodDesc: 0000064281cb8210
Name: TestLib.MyTestClass..cctor()
Not JITTED yet. Use !bpmd -md 0000064281cb8210 to break on run.

0:085> !dumpmd  0000064281cb8210
Method Name: TestLib.MyTestClass..cctor()
Class: 0000064281cd2c40
MethodTable: 0000064281cb8218
mdToken: 06000360
Module: 00000642803f6008
IsJitted: no
CodeAddr: ffffffffffffffff

0:085> !dumpil 0000064281cb8210
ilAddr = 000000001000db65
IL_0000: ldc.i4.1 
IL_0001: stsfld TestLib.MyTestClass::_isFirst
IL_0006: ret 

보는 바와 같이, JIT 컴파일되지도 않았기 때문에 System.AccessViolationException이 발생할만한 상황도 아니었고, 게다가 dumpil 명령어로 확인한 cctor의 코드는 어떤 포인터 연산도 포함하지 않았습니다. clrstack을 봐도 System.AccessViolationException 예외가 발생하기 바로 직전의 메서드는 확인할 수 없었고,

0:085> !clrstack
OS Thread Id: 0xc34 (85)
Child-SP         RetAddr          Call Site
000000000946e070 0000064280bb5719 TestLib.TempWebPage.Page_Load(System.Object, System.EventArgs)
000000000946e0d0 0000064280bb56d4 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000946e100 0000064280bb5675 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
...[생략]...
000000000946e570 000006428066a599 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
000000000946e5c0 0000064280667178 System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
000000000946e630 000006427f5fcda2 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)

Native 콜 스택 결과도 마찬가지였습니다.

0:085> kv
Child-SP          RetAddr           : Args to Child                                                           : Call Site
00000000`0946a798 00000000`77d706af : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
00000000`0946a7a0 00000642`7f494b46 : 00000000`00001a0c 00000000`00000000 00000000`00000000 00000000`ffffffff : kernel32!WaitForSingleObjectEx+0x130
00000000`0946a840 00000642`7f494a4f : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : mscorwks!CLREvent::WaitEx+0x15a
00000000`0946a8a0 00000642`7f8ba79b : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : mscorwks!CLREvent::WaitEx+0x63
00000000`0946a950 00000642`7f8baa01 : 00000002`000003f0 00000000`00000000 00000000`00000006 00000000`0180b228 : mscorwks!Thread::WaitSuspendEventsHelper+0xdb
00000000`0946aa20 00000642`7f7af02c : 00000000`00000048 00000000`0b326010 00000002`000003f0 00000642`7f514eb0 : mscorwks!Thread::WaitSuspendEvents+0x11
00000000`0946aa50 00000642`7f9fb68e : ffffffff`fffffffe 00000642`7f55353b 00000000`00141950 00000000`0b326010 : mscorwks! ?? ::FNODOBFM::`string'+0x2170c
00000000`0946aaa0 00000642`7f966b38 : 00000000`0946abc0 00000000`00000000 00000000`00141950 00000000`00000006 : mscorwks!Thread::RareDisablePreemptiveGC+0x10e
00000000`0946ab40 00000642`7f96701a : 00000000`0b326010 00000642`7f53716c 00000000`0476afd0 00000000`0946c090 : mscorwks!Debugger::SendException+0x518
00000000`0946b110 00000642`7f8341ef : 00000000`036a65b8 00000000`0b326010 00000000`04e038e0 00000642`00000000 : mscorwks!Debugger::FirstChanceManagedException+0x2a
00000000`0946b170 00000642`7f4fe870 : 00000000`036a6580 00000000`0946c090 00000000`0946e070 00000000`00000000 : mscorwks! ?? ::FNODOBFM::`string'+0xa68cf
00000000`0946b3c0 00000642`7f4ffcff : 00000642`81c70532 00000642`81cd2e5c 00000000`0946ced0 00000000`0946c398 : mscorwks!ExceptionTracker::ProcessOSExceptionNotification+0x430
00000000`0946c280 00000000`77ee3d4d : 00000642`00000001 00000000`0946e070 00000000`0946ced0 00000000`00000000 : mscorwks!ProcessCLRException+0x19b
00000000`0946c320 00000000`77ee5857 : 00000000`00000001 00000000`00000001 00000000`0946ced0 00000000`0946dfa0 : ntdll!RtlpExecuteHandlerForException+0xd
00000000`0946c350 00000000`77ef2a3d : fffffadf`b37bfeb0 00000000`0946ca00 00000642`81cb8218 00000642`81cb8218 : ntdll!RtlDispatchException+0x1b4
00000000`0946ca00 00000000`77d4dce0 : 00000000`0b326010 00000642`81cb8218 00000000`e0434f4d 00000000`0b326010 : ntdll!KiUserExceptionDispatch+0x2d (TrapFrame @ 00000000`0946ce08)
00000000`0946cfa0 00000642`7f475c05 : 00000000`0b326010 00000642`81cb8218 00000000`e0434f4d 00000000`0b326010 : kernel32!RaiseException+0x5c
00000000`0946d070 00000642`7f8a5b57 : 00000000`c039d708 00000000`00000000 00000642`00000000 00000642`00000001 : mscorwks!RaiseTheExceptionInternalOnly+0x295
00000000`0946d140 00000642`7f8a6866 : 00002026`00000001 00000642`00000000 00009fca`5c79603c 00000000`0f355128 : mscorwks!RaiseTheException+0x57
00000000`0946d170 00000642`7f929d55 : 00000642`81cb8218 00000642`81cb8218 00000000`00000000 00000000`0a4010e0 : mscorwks!BStrFromString+0x66
00000000`0946d1a0 00000642`7f929d6b : 00000000`c039d708 00000000`0a4010e0 00000000`00000000 00000000`0a4010e0 : mscorwks!RealCOMPlusThrow+0x35
00000000`0946d210 00000642`7f80be5e : 00000642`81cb8218 00000642`81cb8218 00000000`00000000 00000000`0a4010e0 : mscorwks!RealCOMPlusThrow+0xb
00000000`0946d240 00000642`7f97f6f8 : 00000000`000001f0 00000642`81cb8218 00000000`00000191 00000642`803f7630 : mscorwks! ?? ::FNODOBFM::`string'+0x7e53e
00000000`0946dcf0 00000642`7f4d71f2 : 00000000`c00afea8 00000000`00000000 00000000`00000000 00000642`7f4e7d5e : mscorwks!MethodTable::CheckRunClassInitThrowing+0x68
00000000`0946dd30 00000642`7f4c9ebb : 00000000`c00b4188 00000000`00000000 00000000`00000000 00000000`0946e1e0 : mscorwks!MethodDesc::DoPrestub+0x192
00000000`0946dee0 00000642`7f5fcc87 : 00000000`808514e0 00000000`c0023820 00000000`8084d918 00000000`0b326010 : mscorwks!PreStubWorker+0x1eb
00000000`0946dfa0 00000642`81c70532 : 00000000`80851ec0 00000000`80851ed8 00000000`c0023820 00000000`c0023820 : mscorwks!ThePreStubAMD64+0x87
00000000`0946e070 00000642`80bb5719 : 00000000`8084d918 00000000`8084d918 00000000`c0023820 00000642`8080ff12 : 0x642`81c70532
00000000`0946e0d0 00000642`80bb56d4 : 00000000`8084d918 00000642`80b36250 00000000`8084d918 00000000`c0023820 : 0x642`80bb5719
00000000`0946e100 00000642`80bb5675 : 00000000`8084d918 00000642`8080ff12 00000000`80851dd8 00000000`80851dd8 : 0x642`80bb56d4
00000000`0946e130 00000642`80bb5532 : 00000000`808514e0 00000642`80667839 00000000`8084d918 00000000`00000000 : 0x642`80bb5675
00000000`0946e170 00000642`80b220d7 : 00000000`8084d918 00000000`0946e1e8 00000000`c03a6901 00000000`0946e201 : 0x642`80bb5532
00000000`0946e1c0 00000642`80b18c5a : 00000000`8084d918 00000000`8084d901 00000000`c04eb001 00000642`8066c08f : 0x642`80b220d7
00000000`0946e280 00000642`80b18b1e : 00000000`8084d918 00000000`80846f78 00000000`8084d901 00000000`0946e3e0 : 0x642`80b18c5a
00000000`0946e2e0 00000642`80b141c7 : 00000000`8084d918 00000642`80a5c431 00000000`80846f78 00000001`00000001 : 0x642`80b18b1e
00000000`0946e340 00000642`81c6fea4 : 00000000`80846f78 00000000`80846f78 00000000`8084d918 00000000`0946e3e0 : 0x642`80b141c7
00000000`0946e390 00000642`80a5c184 : 00000000`8084d918 00000000`80846f78 00000000`c00030d0 00000642`80660546 : 0x642`81c6fea4
00000000`0946e3c0 00000642`80a229d1 : 00000000`80244a80 c2000001`60008e8c 00000000`80242908 00000000`8084b668 : 0x642`80a5c184
00000000`0946e450 00000642`80a20949 : 00000000`80242908 00000000`80244a80 00000000`0946e4f8 00000642`8046a592 : 0x642`80a229d1
00000000`0946e4d0 00000642`80a2056c : 00000000`802447c8 00000000`00000000 00000000`80032528 00000642`80a204ad : 0x642`80a20949
00000000`0946e570 00000642`8066a599 : 00000000`7fff3c60 00000000`0946e650 48d3681c`1b957ce1 00000000`00000000 : 0x642`80a2056c
00000000`0946e5c0 00000642`80667178 : 00000000`c0002ab8 00000000`80846640 00000000`0946e948 00000000`00000002 : 0x642`8066a599
00000000`0946e630 00000642`7f5fcda2 : 00000000`8003e260 00000000`02fe0950 00000000`00000002 ffffffff`fffffffe : 0x642`80667178
00000000`0946e740 00000642`7f5069f3 : 00000000`0946e820 00000000`0946e8f0 ffffffff`fffffffe 00000000`00000000 : mscorwks!CallDescrWorker+0x82
00000000`0946e7a0 00000642`7f521e10 : 00000000`0946e930 00000000`0946eef0 00000000`00000003 00000000`00000003 : mscorwks!CallDescrWorkerWithHandler+0xd3
00000000`0946e840 00000642`7f52217b : 00000000`03314460 00000000`00081800 00000000`00000000 00000642`00000004 : mscorwks!ForwardCallToManagedMethod+0x160
00000000`0946e8e0 00000642`7f542918 : 00000000`0493cc00 00000000`0b326010 ffffffff`fffffffe 00000000`0b326260 : mscorwks!COMToCLRWorkerBody+0x35b
00000000`0946eb40 00000642`7f496506 : 00000000`00000000 00000000`0946ecb8 00000000`0946ef30 00000000`00000000 : mscorwks!COMToCLRWorkerDebuggerWrapper+0x50
00000000`0946ebb0 00000642`7f5fcf1e : 00000000`0b326010 00000000`0946ef30 00000000`02fd4800 00000000`00000000 : mscorwks!COMToCLRWorker+0x366
00000000`0946eea0 00000642`fff582b3 : 00000000`04dbff20 00000000`02fe0950 00000000`00000002 00000000`0946ef90 : mscorwks!GenericComCallStub+0x5e
00000000`0946ef50 00000642`fff58693 : ffffffff`fffffffe 00000000`02fe0950 00000000`0a1ab230 00000000`00000001 : webengine!HttpCompletion::ProcessRequestInManagedCode+0x2a3
00000000`0946f400 00000642`fff9ad04 : 00000642`7fc08ca8 00000642`7fc08ca8 00000642`fff9ace0 00000000`00000001 : webengine!HttpCompletion::ProcessCompletion+0x63
00000000`0946f440 00000642`7f48feb7 : ffffffff`fffffffe 00000000`00000001 00000000`00000000 00000000`00000001 : webengine!CorThreadPoolWorkitemCallback+0x24
00000000`0946f470 00000642`7f4a7bea : 00000000`00000000 00000000`00000000 00000000`00000002 00000000`0b326010 : mscorwks!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x157
00000000`0946f510 00000642`7f421304 : 00000000`00000000 00000000`00000000 00000000`0946ff50 00000000`00000000 : mscorwks!ThreadpoolMgr::WorkerThreadStart+0x1ba
00000000`0946f5b0 00000000`77d6b8ca : 00000000`77d6b890 00000000`00000000 00000000`00000000 00000000`0946ffa8 : mscorwks!Thread::intermediateThreadProc+0x78
00000000`0946ff80 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadStart+0x3a

상황을 보아하니, 아마도 System.TypeInitializationException 예외가 잡히는 시점에는 이미 오류 문맥을 벗어난 것이 아닌가... 하는 생각이 들었습니다. 어쨌든 System.TypeInitializationException 예외 이전에 System.AccessViolationException 예외가 발생한다는 사실을 알았으므로 procdump.exe를 이용해 다시 한번 System.AccessViolationException을 조건으로 덤프를 떴습니다.

procdump -ma  -e 1 -f AccessVio* 3628

sos 확장도 다시 로드하고 System.AccessViolationException 예외가 발생한 스레드로 문맥 전환을 한 후, clrstack 명령어를 확인했지만 여전히 관리 코드내에서의 직접적인 원인은 나오지 않았습니다.

0:048> !clrstack
OS Thread Id: 0xcf0 (48)
*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for TestUnmanaged64.dll - 
Child-SP         RetAddr          Call Site
000000000dcfdd70 0000064280b2e5b9 TestLib.TempWebPage.Page_Load(System.Object, System.EventArgs)
000000000dcfddd0 0000064280b2e574 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000dcfde00 0000064280b2e515 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
000000000dcfde30 0000064280b2e3d2 System.Web.UI.Control.OnLoad(System.EventArgs)
000000000dcfde70 0000064280b26337 System.Web.UI.Control.LoadRecursive()
000000000dcfdec0 0000064280b1855a System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
000000000dcfdf80 0000064280b1841e System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
000000000dcfdfe0 0000064280b13b47 System.Web.UI.Page.ProcessRequest()
000000000dcfe040 0000064281896f94 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
000000000dcfe090 0000064280a5bbb4 ASP.j5_TempWebPage_aspx.ProcessRequest(System.Web.HttpContext)
000000000dcfe0c0 0000064280a22371 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
000000000dcfe150 0000064280a202e9 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
000000000dcfe1d0 000006428080fc1c System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)
000000000dcfe270 000006428066a599 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
000000000dcfe2c0 0000064280667178 System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
000000000dcfe330 000006427f5fcda2 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)

그런데, native 콜 스택에는 제가 작성한 함수의 콜 스택이 나왔습니다.

0:048> kv
Child-SP          RetAddr           : Args to Child                                                           : Call Site
00000000`0dcf2e78 00000000`77d706af : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
...[생략]...
00000000`0dcf3220 00000642`7f96701a : 00000000`067a11d0 00000642`7f53716c 00000000`00000001 00000000`00000000 : mscorwks!Debugger::SendException+0x518
00000000`0dcf37f0 00000642`7f8341ef : 00000000`0383de98 00000000`067a11d0 00000000`05022198 00000642`00000000 : mscorwks!Debugger::FirstChanceManagedException+0x2a
00000000`0dcf3850 00000642`7f4fe870 : 00000000`0383de60 00000000`0dcf4770 00000000`0dcfdd70 00000000`00000000 : mscorwks! ?? ::FNODOBFM::`string'+0xa68cf
00000000`0dcf3aa0 00000642`7f4ffcff : 00000642`818976b2 00000642`81c8613c 00000000`0dcf55b0 00000000`0dcf4a78 : mscorwks!ExceptionTracker::ProcessOSExceptionNotification+0x430
00000000`0dcf4960 00000000`77ee3d4d : 00000642`00000000 00000000`0dcfdd70 00000000`0dcf55b0 00000000`00000000 : mscorwks!ProcessCLRException+0x19b
00000000`0dcf4a00 00000000`77ee5857 : 00000000`00000001 00000000`00000000 00000000`0dcf55b0 00000000`0dcfdca0 : ntdll!RtlpExecuteHandlerForException+0xd
00000000`0dcf4a30 00000000`77ef2a3d : 00000000`00000000 00000000`0dcf50e0 00000000`000000c0 00000000`0dcf7960 : ntdll!RtlDispatchException+0x1b4
00000000`0dcf50e0 00000001`80013f70 : 00000000`000000bf 00000000`0a7c4f40 00000001`800809c0 00000000`00000001 : ntdll!KiUserExceptionDispatch+0x2d (TrapFrame @ 00000000`0dcf54e8)
00000000`0dcf5680 00000001`8001b21c : 00000000`0000001c 00000000`0000001c 00000001`80081e20 00000000`000000c0 : TestUnmanaged64+0x13f70
00000000`0dcf5740 00000001`8001379d : 00000000`0dcf63e0 00000000`00000000 00000001`800813b8 00000000`0dcf64c0 : TestUnmanaged64+0x1b21c
00000000`0dcf61b0 00000001`80026848 : 00000000`00000200 00000000`00000000 00720065`00660069 0057002e`00300034 : TestUnmanaged64+0x1379d
00000000`0dcf7910 00000001`8002427a : 00000000`09e568a0 00000000`00000000 00000000`00000000 00000642`803f6008 : TestUnmanaged64+0x26848
00000000`0dcf8040 00000001`800228ef : 00000000`00158330 00000000`0015e208 00000000`0015e208 00000000`06612ed0 : TestUnmanaged64+0x2427a
00000000`0dcfd7d0 00000642`ff8d6443 : 00000000`0aa3b398 00000642`7fc136c0 00000000`0dcfd8b0 00000642`7f4bb54e : TestUnmanaged64+0x228ef
...[생략]...

단지 PDB가 올라오지 않아 "TestUnmanaged64+0x1b21c" 와 같은 식으로만 콜 스택이 나오는 군요. 실제로 lm 으로 확인해 보니 해당 DLL의 pdb가 deferred로 표시되어 있습니다.

0:048> lm
start             end                 module name
00000000`00400000 00000000`00406000   w3wp       (deferred)             
...[생략]...     
00000000`13760000 00000000`1395b000   sybdrvado20   (deferred)             
00000000`13970000 00000000`139a3000   WebTestHelper64   (deferred)             
00000000`13a60000 00000000`13a6a000   App_Web_h4pa_7ul   (deferred)       
00000001`80000000 00000001`800c3000   TestUnmanaged64   (deferred)         
...[생략]...     
000007ff`7fee0000 000007ff`7ffe9000   advapi32   (deferred)             

Unloaded modules:
000007ff`7b0f0000 000007ff`7b20e000   RichEd20.dll
000007ff`79230000 000007ff`7924e000   digest.dll
000007ff`7dd50000 000007ff`7dd95000   schannel.dll
00000642`ff4a0000 00000642`ff4aa000   culture.dll

재미있는 것은, TestUnmanaged64.dll이 위치한 동일한 폴더에 TestUnmanaged64.pdb 파일이 있었는데도 ".realod -f" 명령어로는 PDB가 올라오지 않았다는 점입니다.

0:048> .reload -f
...................................*** ERROR: Module load completed but symbols could not be loaded for iisres.dll


Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

.........................*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for TestUnmanaged64.dll - 

어쩔 수 없군요. 이럴 때는 noisy 모드를 켜고,

0:048> !sym noisy
noisy mode - symbol prompts on

다시 한번 .reload -f 명령어를 내리면 windbg가 찾으려는 PDB 경로가 함께 출력되므로 이를 검사하면 됩니다.

...[생략]...
SYMSRV:  d:\symbols\TestUnmanaged64.pdb\91F30530ADD344D3895F7478DC17499C1\TestUnmanaged64.pdb not found
SYMSRV:  http://msdl.microsoft.com/download/symbols/TestUnmanaged64.pdb/91F30530ADD344D3895F7478DC17499C1/TestUnmanaged64.pdb not found
DBGHELP: D:\TestWebSite\TestUnmanaged\bin\Release\TestUnmanaged64.pdb - file not found
*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for TestUnmanaged64.dll - 
DBGHELP: TestUnmanaged64 - export symbols
...[생략]...

저 3개의 경로 중 하나에만 넣어주면 되는데요. 제 경우에는 그냥 "D:\TestWebSite\TestUnmanaged\bin\Release\TestUnmanaged64.pdb"로 위치시키고 다시 .reload -f를 내려 로드를 했습니다. 그럼, 이번에는 다음과 같이 "private symbols & lines" 메시지를 통해 PDB를 정상적으로 로드했음을 확인할 수 있습니다.

...[생략]...
SYMSRV:  d:\symbols\TestUnmanaged64.pdb\91F30530ADD344D3895F7478DC17499C1\TestUnmanaged64.pdb not found
SYMSRV:  http://msdl.microsoft.com/download/symbols/TestUnmanaged64.pdb/91F30530ADD344D3895F7478DC17499C1/TestUnmanaged64.pdb not found
*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
DBGHELP: TestUnmanaged64 - private symbols & lines
...[생략]...

이 상태에서 kv 콜 스택을 확인하면... 와~~~ ^^

0:048> kv
DBGHELP: kernel32 - public symbols  
         d:\symbols\kernel32.pdb\19C002F7F64C463C91C1E8CEDF84B0252\kernel32.pdb
Child-SP          RetAddr           : Args to Child                                                           : Call Site
00000000`0dcf2e78 00000000`77d706af : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
00000000`0dcf2e80 00000642`7f494b46 : 00000000`00000eb8 00000000`00000000 00000000`00000000 00000000`ffffffff : kernel32!WaitForSingleObjectEx+0x130
...[생략]....
00000000`0dcf5680 00000001`8001b21c : 00000000`0000001c 00000000`0000001c 00000001`80081e20 00000000`000000c0 : TestUnmanaged64!MyNativeType::TestMethod+0x60 [d:\TestWebSite\TestUnmanaged64\MyNativeType.cpp @ 2341]

...[생략]....
00000000`0dcfff80 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadStart+0x3a

소스 코드 라인 번호까지 나왔으니... 게임 끝입니다. ^^




이 문제에서 재미있었던 점이 하나 있는데요. 해당 문제는 Unmanaged 환경의 C++ 코드에서 발생했기 때문에 사실 C/C++의 AccessViolation 예외가 발생하는 것이 정상입니다. 대충 이런 식이어야 하는데요.

Unhandled exception at 0x0fc716b7 (TestUnmanaged64.dll) in w3wp.exe: 0xC0000005: Access violation.

그런데, 쌩뚱맞게도 그것이 Managed 수준으로 넘어와 System.AccessViolationException 예외가 던져졌기 때문에 문제 파악에 혼란이 온 것입니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2024-11-11 08시41분
The case of a program that crashed on its first instruction
; https://devblogs.microsoft.com/oldnewthing/20241108-00/?p=110490
정성태

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13838정성태12/4/2024644오류 유형: 935. Windbg - Breakpoint 0's offset expression evaluation failed.
13837정성태12/3/2024722디버깅 기술: 204. Windbg - 윈도우 핸들 테이블 (3) - Windows 10 이상인 경우
13836정성태12/3/2024953디버깅 기술: 203. Windbg - x64 가상 주소를 물리 주소로 변환 (페이지 크기가 2MB인 경우)
13835정성태12/2/20241002오류 유형: 934. Azure - rm: cannot remove '...': Directory not empty
13834정성태11/29/20241078Windows: 275. C# - CUI 애플리케이션과 Console 윈도우 (Windows 10 미만의 Classic Console 모드인 경우)파일 다운로드1
13833정성태11/29/20241096개발 환경 구성: 737. Azure Web App에서 Scale-out으로 늘어난 리눅스 인스턴스에 SSH 접속하는 방법
13832정성태11/27/20241111Windows: 274. Windows 7부터 도입한 conhost.exe
13831정성태11/27/2024978Linux: 111. eBPF - BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_MAP_TYPE_RINGBUF에 대한 다양한 용어들
13830정성태11/25/20241086개발 환경 구성: 736. 파이썬 웹 앱을 Azure App Service에 배포하기
13829정성태11/25/20241027스크립트: 67. 파이썬 - Windows 버전에서 함께 설치되는 py.exe
13828정성태11/25/20241048개발 환경 구성: 735. Azure - 압축 파일을 이용한 web app 배포 시 디렉터리 구분이 안 되는 문제파일 다운로드1
13827정성태11/25/20241118Windows: 273. Windows 환경의 파일 압축 방법 (tar, Compress-Archive)
13826정성태11/21/20241191닷넷: 2313. C# - (비밀번호 등의) Console로부터 입력받을 때 문자열 출력 숨기기(echo 끄기)파일 다운로드1
13825정성태11/21/20241145Linux: 110. eBPF / bpf2go - BPF_RINGBUF_OUTPUT / BPF_MAP_TYPE_RINGBUF 사용법
13824정성태11/20/20241100Linux: 109. eBPF / bpf2go - BPF_PERF_OUTPUT / BPF_MAP_TYPE_PERF_EVENT_ARRAY 사용법
13823정성태11/20/20241085개발 환경 구성: 734. Ubuntu에 docker, kubernetes (k3s) 설치
13822정성태11/20/20241045개발 환경 구성: 733. Windbg - VirtualBox VM의 커널 디버거 연결 시 COM 포트가 없는 경우
13821정성태11/18/20241171Linux: 108. Linux와 Windows의 프로세스/스레드 ID 관리 방식
13820정성태11/18/20241128VS.NET IDE: 195. Visual C++ - C# 프로젝트처럼 CopyToOutputDirectory 항목을 추가하는 방법
13819정성태11/15/20241139Linux: 107. eBPF - libbpf CO-RE의 CONFIG_DEBUG_INFO_BTF 빌드 여부에 대한 의존성
13818정성태11/15/20241216Windows: 272. Windows 11 24H2 - sudo 추가
13817정성태11/14/20241101Linux: 106. eBPF / bpf2go - (BPF_MAP_TYPE_HASH) Map을 이용한 전역 변수 구현
13816정성태11/14/20241174닷넷: 2312. C#, C++ - Windows / Linux 환경의 Thread Name 설정파일 다운로드1
13815정성태11/13/20241102Linux: 105. eBPF - bpf2go에서 전역 변수 설정 방법
13814정성태11/13/20241215닷넷: 2311. C# - Windows / Linux 환경에서 Native Thread ID 가져오기파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...