System.Runtime.InteropServices.SEHException - 0x80004005
SEHException은 "unmanaged code" 영역에서 발생한 것으로 .NET 예외에는 매핑이 되지 않아 필요한 문맥 정보가 그다지 많지 않습니다.
(여러 가지 발생 상황이 있겠지만) 간단한 예로 다음의 코드로 재현하는 것이 가능합니다.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
static void Main(string[] args)
{
int pid = Process.GetCurrentProcess().Id;
while (true)
{
try
{
Process proc = Process.GetProcessById(pid);
Console.Write(".");
CloseHandle(proc.Handle); // 핸들을 닫음
} catch { }
// GC.Collect(2, GCCollectionMode.Forced);
Thread.Sleep(1000);
}
}
}
}
위의 코드를 F5 디버그 모드로 실행하면 어느 순간 다음과 같은 예외가 발생합니다. (또는, 위의 코드에서 주석 처리한 GC.Collect를 해제하면 곧바로 발생합니다.)
System.Runtime.InteropServices.SEHException occurred
HResult=0x80004005
Message=External component has thrown an exception.
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
- $exception {"External component has thrown an exception."} System.Runtime.InteropServices.SEHException
+ Data {System.Collections.ListDictionaryInternal} System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
ErrorCode -2147467259 int
HResult -2147467259 int
HelpLink null string
+ IPForWatsonBuckets 0x0000000000000000 System.UIntPtr
+ InnerException null System.Exception
IsTransient false bool
Message "External component has thrown an exception." string
RemoteStackTrace null string
Source "System" string
StackTrace " at Microsoft.Win32.SafeNativeMethods.CloseHandle(IntPtr handle)\r\n at Microsoft.Win32.SafeHandles.SafeProcessHandle.ReleaseHandle()\r\n at System.Runtime.InteropServices.SafeHandle.InternalFinalize()\r\n at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing)\r\n at System.Runtime.InteropServices.SafeHandle.Finalize()" string
+ TargetSite {Boolean CloseHandle(IntPtr)} System.Reflection.MethodBase {System.Reflection.RuntimeMethodInfo}
+ WatsonBuckets {byte[5616]} object {byte[]}
_HResult -2147467259 int
_className "System.Runtime.InteropServices.SEHException" string
+ _data {System.Collections.ListDictionaryInternal} System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
_dynamicMethods null object
+ _exceptionMethod {Boolean CloseHandle(IntPtr)} System.Reflection.MethodBase {System.Reflection.RuntimeMethodInfo}
_exceptionMethodString null string
_helpURL null string
+ _innerException null System.Exception
+ _ipForWatsonBuckets 0x0000000000000000 System.UIntPtr
_message "External component has thrown an exception." string
_remoteStackIndex 0 int
_remoteStackTraceString null string
+ _safeSerializationManager {System.Runtime.Serialization.SafeSerializationManager} System.Runtime.Serialization.SafeSerializationManager
_source "System" string
+ _stackTrace {sbyte[192]} object {sbyte[]}
_stackTraceString null string
+ _watsonBuckets {byte[5616]} object {byte[]}
_xcode -532462766 int
+ _xptrs 0x0000000000000000 System.IntPtr
+ Static members
GC가 수행된 후 연결되는 Finalizer 실행에 의해 발생하는 것이므로 일반적인 call stack 정보를 알아낼 수는 없습니다. 게다가 Finalizer의 수행 시점이 불확실하기 때문에 실제 운영 상황에서는 프로세스가 어느 순간 아무 이유 없이 종료하는 현상처럼 보이게 됩니다.
다행히, 이번처럼 간단한 예제의 경우에는 콜 스택을 통해 Handle 관리가 잘못되었다는 것을 짐작할 수 있으므로 CloseHandle(proc.Handle) 코드를 삭제하는 것으로 해결할 수 있지만, 운이 나쁘면 디버깅에 장난 아닌 시간을 들여야 할지도 모릅니다.
참고로, 위의 코드를 디버거 없이 단독 실행하는 경우에는 SEHException 예외가 발생하지 않습니다. 이걸 다행이라고 해야 할지는 모르겠군요. ^^
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]