λ°˜μ‘ν˜•

ꡬ쑰적 μ˜ˆμ™Έ 처리(SEH)λž€?

ꡬ쑰적 μ˜ˆμ™Έ 처리(μ΄ν•˜ SEH)λŠ” ν•˜λ“œμ›¨μ–΄μ™€ μ†Œν”„νŠΈμ›¨μ–΄ μ˜ˆμ™Έλ₯Ό λͺ¨λ‘ μ²˜λ¦¬ν•˜λŠ” Microsoft Windows의 κΈ°λ³Έ μ˜ˆμ™Έ 처리 λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€. ν•˜λ“œμ›¨μ–΄ μ˜ˆμ™ΈλŠ” μ˜ˆμ™Έκ°€ λ°œμƒν•œ 주체가 CPU와 같은 ν•˜λ“œμ›¨μ–΄λΌλŠ” 것이고, μ†Œν”„νŠΈμ›¨μ–΄ μ˜ˆμ™ΈλŠ” μ‚¬μš©μžκ°€ μž‘μ„±ν•œ μ†Œν”„νŠΈμ›¨μ–΄ 및 μš΄μ˜μ²΄μ œκ°€ μ˜ˆμ™Έμ˜ μ£Όμ²΄λΌλŠ” μ˜λ―Έμž…λ‹ˆλ‹€.

μ’€ 더 μ‰¬μš΄ 예λ₯Ό λ“€μžλ©΄, μ–΄λ–€ 수λ₯Ό 0으둜 λ‚˜λˆ„λŠ” μ—°μ‚°μ΄λ‚˜ μ ‘κ·Όν•  수 μ—†λŠ” λ©”λͺ¨λ¦¬μ— 접근을 μ‹œλ„ν•˜λŠ” λͺ…λ Ήμ–΄λ₯Ό μ‹€ν–‰ν•œλ‹€λ©΄ ν•˜λ“œμ›¨μ–΄ μ˜ˆμ™Έκ°€ λ°œμƒν•˜κ³ , μœ νš¨ν•˜μ§€ μ•Šμ€ μΈμžμ— 값을 지정할 λ•Œ μ†Œν”„νŠΈμ›¨μ–΄ μ˜ˆμ™Έκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이처럼, ν•˜λ“œμ›¨μ–΄μ™€ μ†Œν”„νŠΈμ›¨μ–΄ μ˜ˆμ™Έλ₯Ό λͺ¨λ‘ μ²˜λ¦¬ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ΄ SEHμž…λ‹ˆλ‹€.

https://docs.microsoft.com/ko-kr/windows/win32/debug/structured-exception-handling

 

ꡬ쑰적 μ˜ˆμ™Έ 처리 - Win32 apps

μ˜ˆμ™ΈλŠ” ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰ν•˜λŠ” λ™μ•ˆ λ°œμƒν•˜λŠ” 이벀트둜, 정상적인 μ œμ–΄ 흐름 μ™ΈλΆ€μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•΄μ•Ό ν•©λ‹ˆλ‹€.

docs.microsoft.com

사싀 일반 μ‘μš© ν”„λ‘œκ·Έλž¨ 개발자라면 SEH에 λŒ€ν•΄ 깊게 μ•Œ ν•„μš”λŠ” μ—†λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. SEHλŠ” 주둜 운영체제λ₯Ό μ•ˆμ •μ μœΌλ‘œ κ°œλ°œν•˜κΈ° μœ„ν•œ μ˜ˆμ™Έ 처리둜, 일반 μ‘μš© ν”„λ‘œκ·Έλž¨ κ°œλ°œμžλŠ” μ–Έμ–΄μ—μ„œ μ§€μ›ν•˜λŠ” μ˜ˆμ™Έ 처리λ₯Ό 잘 닀뀄야 ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, C++ ν”„λ‘œκ·Έλž¨μ€ C++ 문법인 try-catch, throwλ₯Ό μ΄μš©ν•˜μ—¬ μ˜ˆμ™Έλ₯Ό 닀루면 λ©λ‹ˆλ‹€. λ¬Όλ‘ , SEHλ₯Ό μ‚¬μš©ν•΄λ„ λ¬΄λ°©ν•©λ‹ˆλ‹€.

참고둜, C++ μ˜ˆμ™Έ μ²˜λ¦¬λŠ” λ‚΄λΆ€μ μœΌλ‘œ μ»΄νŒŒμΌλŸ¬μ™€ μœˆλ„μš°κ°€ μ§€μ›ν•˜λŠ” SEH κΈ°λŠ₯을 μ΄μš©ν•˜μ—¬ κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

SEH κΈ°λ³Έ 문법

SEHλŠ” 두 가지 μ£Όμš” κΈ°λŠ₯으둜 κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. λ°”λ‘œ, μ’…λ£Œ μ²˜λ¦¬κΈ°μ™€ μ˜ˆμ™Έ μ²˜λ¦¬κΈ°μž…λ‹ˆλ‹€. 각 μ²˜λ¦¬μ— λŒ€ν•΄ μ°¨λ‘€λŒ€λ‘œ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

1. μ’…λ£Œ 처리기(Termination Handler)

μ’…λ£Œ μ²˜λ¦¬κΈ°λŠ” __try 블둝 λ‚΄μ˜ μ œμ–΄κ°€ μ–΄λ–»κ²Œ λΉ μ Έλ‚˜μ˜€λ“  __finally λΈ”λ‘μ˜ μ½”λ“œκ°€ λ°˜λ“œμ‹œ μˆ˜ν–‰λ  κ²ƒμ΄λΌλŠ” 것을 보μž₯ν•©λ‹ˆλ‹€. μ•„λž˜ μ˜ˆμ œλŠ” μ’…λ£Œ 처리기 SEH κ΅¬λ¬Έμž…λ‹ˆλ‹€.

__try
{
	//...
}
__finally
{
	//μ’…λ£Œ 처리기
	//...
}

운영 μ²΄μ œμ™€ μ»΄νŒŒμΌλŸ¬λŠ” 항상 μ’…λ£Œ 처리기의 μ½”λ“œκ°€ μˆ˜ν–‰λ˜λ„λ‘ 보μž₯ν•©λ‹ˆλ‹€. 단, ExitProcess, ExitThread, TerminateProcess, TerminateThread와 같은 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ ν”„λ‘œμ„ΈμŠ€λ‚˜ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ˜λŠ” κ²½μš°λŠ” μ œμ™Έν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ 상황을 μ œμ™Έν•˜κ³€, __try 블둝 λ‚΄μ—μ„œ return, goto와 같은 문을 ν˜ΈμΆœν•˜λ”λΌλ„ μ’…λ£Œ μ²˜λ¦¬κΈ°λŠ” 항상 ν˜ΈμΆœλ©λ‹ˆλ‹€.

그런데, μ–΄λ–»κ²Œ μ’…λ£Œ 처리기인 __finally 블둝이 항상 ν˜ΈμΆœλ˜λŠ” κ²ƒμΌκΉŒμš”? μ΄λŠ”, μ»΄νŒŒμΌλŸ¬κ°€ __try 블둝 λ‚΄μ—μ„œ λΉ μ Έλ‚˜κ°€κΈ° 전에 __finally 블둝을 λ°˜λ“œμ‹œ μˆ˜ν–‰λ  수 μžˆλ„λ‘ 좔가적인 μ½”λ“œλ₯Ό μƒμ„±ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 이λ₯Ό 둜컬 μ–Έμ™€μΈλ“œ(Local Unwind)라고 ν•©λ‹ˆλ‹€.

둜컬 μ–Έμ™€μΈλ“œ(Local Unwind)

μ•žμ„œ μ„€λͺ…ν•œ λŒ€λ‘œ, μ‹œμŠ€ν…œμ΄ __try 블둝을 λΉ μ Έλ‚˜κ°€κΈ° 전에 __finally 블둝을 λ¨Όμ € μˆ˜ν–‰ν•΄μ•Ό ν•˜λŠ” μ½”λ“œλ₯Ό μΆ”κ°€λ‘œ μƒμ„±ν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. 그런데 'μ½”λ“œλ₯Ό μΆ”κ°€λ‘œ μƒμ„±ν•œλ‹€'λΌλŠ” 쑰건이 λˆˆμ— λ„λŠ”λ°μš”. 좔가적인 μ½”λ“œλ₯Ό μƒμ„±ν•œλ‹€λŠ” 것은 κ²°κ΅­ λΉ„μš©μ΄ λ°œμƒν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 그리고 λ°œμƒν•œ λΉ„μš©μ€ ν”„λ‘œκ·Έλž¨ μˆ˜ν–‰ μ„±λŠ₯에도 쒋지 μ•Šμ€ 영ν–₯을 쀄 수 μžˆμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ, 둜컬 μ–Έμ™€μΈλ“œκ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ μ œμ–΄μ˜ 흐름을 μžμ—°μŠ€λŸ½κ²Œ μž‘μ„±ν•΄μ•Ό ν•©λ‹ˆλ‹€. __try 블둝을 μˆ˜ν–‰ν•˜κ³  μžμ—°μŠ€λŸ½κ²Œ __finally 블둝을 μˆ˜ν–‰ν•˜λŠ” 것이 λΉ„μš©μ„ μ΅œμ†Œν™”ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

또 ν•˜λ‚˜μ˜ 주의 μ‚¬ν•­μœΌλ‘œ, __try λΈ”λ‘μ—μ„œλŠ” μ„œλ‘˜λŸ¬μ„œ λΉ μ Έλ‚˜κ°€λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ μ•ŠλŠ” 것을 ꢌμž₯ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, return, goto, continue, break와 같은 λ¬Έμž₯을 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이 κ°€μž₯ 쒋은 λ°©λ²•μž…λ‹ˆλ‹€. μ»΄νŒŒμΌλŸ¬κ°€ 둜컬 μ–Έμ™€μΈλ“œμ™€ 같은 μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ§€ μ•Šμ•„λ„ 되기 λ•Œλ¬Έμ—, μ’€ 더 μž‘μ€ μ½”λ“œλ₯Ό 생성할 수 있고 μ΄λŠ” μ΅œμ†Œν•œμ˜ λΉ„μš©μœΌλ‘œ μ½”λ“œλ₯Ό μ’€ 더 λΉ λ₯΄κ²Œ λ™μž‘ν•˜λ„λ‘ ν•  수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

__leave ν‚€μ›Œλ“œ

__try 블둝 λ‚΄μ—μ„œ __leave ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ __try λΈ”λ‘μ˜ κ°€μž₯ λ§ˆμ§€λ§‰μœΌλ‘œ μ΄λ™ν•˜κ²Œ λ©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ μ•žμ—μ„œ μ„€λͺ…ν•œ κ²ƒμ²˜λŸΌ, μ½”λ“œ μˆ˜ν–‰ 흐름이 μžμ—°μŠ€λŸ½κ²Œ __try λΈ”λ‘μ—μ„œ __finally λΈ”λ‘μœΌλ‘œ μ΄λ™ν•˜κΈ° λ•Œλ¬Έμ— μ–΄λ– ν•œ μΆ”κ°€ λΉ„μš©μ΄ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

2. μ˜ˆμ™Έ 처리기(Exception Handler)

μ˜ˆμ™Έ μ²˜λ¦¬κΈ°λŠ” __try λΈ”λ‘μ˜ μ½”λ“œλ₯Ό μˆ˜ν–‰ν•˜λ˜ 쀑 μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ __except λ¬Έμ—μ„œ ν•„ν„°λ₯Ό ν‰κ°€ν•˜μ—¬ μΆ”κ°€ λ™μž‘μ„ μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€. μ•„λž˜ μ˜ˆμ œλŠ” μ˜ˆμ™Έ 처리기 SEH κ΅¬λ¬Έμž…λ‹ˆλ‹€.

__try
{
	//...
}
__except (μ˜ˆμ™Έ ν•„ν„°)
	//μ˜ˆμ™Έ 처리기
	//...
}

μ˜ˆμ™Έ 처리기의 μ˜ˆμ™Έ 필터에 λŒ€ν•΄ μ„€λͺ…ν•  λ‚΄μš©μ΄ 더 μžˆμŠ΅λ‹ˆλ‹€. 깊게 λ“€μ–΄κ°€κΈ° 전에, SEH 문법에 λŒ€ν•΄ 잠깐 μ •λ¦¬ν•˜κ³  μ„€λͺ…을 μ΄μ–΄κ°€κ² μŠ΅λ‹ˆλ‹€.

SEH 문법 쀑간 정리

SEH 문법인 __try 블둝을 λ§Œλ“€λ©΄ λ°˜λ“œμ‹œ μ’…λ£Œ 처리기인 __finally 블둝 λ˜λŠ” μ˜ˆμ™Έ 처리기인 __except 블둝이 따라와야 ν•©λ‹ˆλ‹€. __try 블둝은 __finally 블둝과 __except 블둝을 λ™μ‹œμ— κ°€μ§ˆ 수 μ—†μŠ΅λ‹ˆλ‹€. 그리고 μ—¬λŸ¬ 개의 __except 블둝도 κ°€μ§ˆ 수 μ—†μŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ __try-__finally 블둝 내에 __try-__except 블둝을 ν¬ν•¨μ‹œν‚€κ±°λ‚˜ λ˜λŠ” κ·Έ λ°˜λŒ€λ‘œ κ΅¬μ„±ν•˜λŠ” 것은 κ°€λŠ₯ν•©λ‹ˆλ‹€.

3. μ˜ˆμ™Έ ν•„ν„°

κ³„μ†ν•΄μ„œ μ˜ˆμ™Έ 처리기의 μ˜ˆμ™Έ 필터에 λŒ€ν•΄ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€. μ˜ˆμ™Έ ν•„ν„°λŠ” 총 μ„Έ 가지λ₯Ό μ œκ³΅ν•˜λ©°, 각 ν•„ν„°λ§ˆλ‹€ μ„œλ‘œ λ‹€λ₯Έ λ™μž‘μ„ μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€.

3-1. EXCEPTION_EXECUTE_HANDLER

__try
{
	//...
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
	//μ˜ˆμ™Έ 처리 μˆ˜ν–‰
    //...
}

κΈ€λ‘œλ²Œ μ–Έμ™€μΈλ“œ(Global Unwind)λ₯Ό μˆ˜ν–‰ν•œ ν›„ __except 블둝을 μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€. __except λΈ”λ‘μ˜ μ½”λ“œκ°€ λͺ¨λ‘ μˆ˜ν–‰λ˜κ³  λ‚˜λ©΄ __except λ°”λ‘œ λ‹€μŒμ˜ μ½”λ“œλ₯Ό μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€.

κΈ€λ‘œλ²Œ μ–Έμ™€μΈλ“œ(Global Unwind)

μ•žμ—μ„œ μ’…λ£Œ 처리기λ₯Ό μ„€λͺ…ν•  λ•Œ 둜컬 μ–Έμ™€μΈλ“œλ₯Ό μ„€λͺ…ν–ˆμ—ˆμŠ΅λ‹ˆλ‹€. 이름이 λΉ„μŠ·ν•œ κΈ€λ‘œλ²Œ μ–Έμ™€μΈλ“œλ₯Ό μ™œ μ§€κΈˆ μ–ΈκΈ‰ν–ˆλƒλ©΄, κΈ€λ‘œλ²Œ μ–Έμ™€μΈλ“œλŠ” μ˜ˆμ™Έ ν•„ν„°κ°€ EXCEPTION_EXECUTE_HANDLER 일 λ•Œ λ™μž‘ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. μ˜ˆμ™Έ ν•„ν„°κ°€ EXCEPTION_EXECUTE_HANDLER둜 ν‰κ°€λ˜λ©΄ __try-__except 블둝 λ‚΄μ˜ λͺ¨λ“  __try-__finally 블둝을 μˆ˜ν–‰ν•˜λŠ” 것을 κΈ€λ‘œλ²Œ μ–Έμ™€μΈλ“œλΌκ³  ν•©λ‹ˆλ‹€.

κΈ€λ‘œλ²Œ-μ–Έμ™€μΈλ“œ-μˆ˜ν–‰-흐름
κΈ€λ‘œλ²Œ μ–Έμ™€μΈλ“œ μˆ˜ν–‰ 흐름

3-2. EXCEPTION_CONTINUE_EXECUTION

__try
{
	//...
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{
	//μ˜ˆμ™Έ 처리 μˆ˜ν–‰
    //...
}

μ˜ˆμ™Έ ν•„ν„°κ°€ EXCEPTION_CONTINUE_EXECUTION둜 ν‰κ°€λ˜λ©΄ μ˜ˆμ™Έλ₯Ό λ°œμƒν–ˆλ˜ μ½”λ“œλ₯Ό λ‹€μ‹œ ν•œλ²ˆ μˆ˜ν–‰ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. λ§Œμ•½, μ˜ˆμ™Έ λ°œμƒ ν›„ μ μ ˆν•œ μ‘°μΉ˜κ°€ 취해지지 μ•Šμ•˜λ‹€λ©΄ λ‹€μ‹œ λ¬Έμ œκ°€ λ°œμƒν•˜κ²Œ 되겠죠. 이 경우 또 λ‹€λ₯Έ μ˜ˆμ™Έκ°€ λ°œμƒν•  μˆ˜λ„ 있고 λ˜λŠ” λ¬΄ν•œ 루프에 빠질 κ°€λŠ₯성도 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 곧 디버깅이 μ–΄λ €μ›Œ 문제 해결에 어렀움이 λ°œμƒν•˜κ² μ£ .

3-3. EXCEPTION_CONTINUE_SEARCH

__try
{
	//...
}
__except(EXCEPTION_CONTINUE_SEARCH)
{
	//μ˜ˆμ™Έ 처리 μˆ˜ν–‰
    //...
}

μ˜ˆμ™Έ ν•„ν„°κ°€ EXCEPTION_CONTINUE_SEARCH둜 ν‰κ°€λ˜λ©΄, κ°€μž₯ μ΅œκ·Όμ— μ§„μž…ν–ˆλ˜ __try 블둝 쀑 __except 블둝을 가진 곳으둜 μ΄λ™ν•˜μ—¬ μ˜ˆμ™Έ ν•„ν„°λ₯Ό ν‰κ°€ν•˜κ²Œ λ©λ‹ˆλ‹€. __try 블둝이 __finally 블둝을 가지고 μžˆλŠ” 경우 검색 λŒ€μƒμ—μ„œ μ œμ™Έλ©λ‹ˆλ‹€.

μ˜ˆμ™Έκ°€ μ²˜λ¦¬λ˜λŠ” 전체 흐름

μ•žμ—μ„œ μ–ΈκΈ‰ν•œ 각 μ˜ˆμ™Έ ν•„ν„°μ˜ λ™μž‘ 흐름을 ν•œλˆˆμ— 정리해 λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ˜ˆμ™Έκ°€-μ²˜λ¦¬λ˜λŠ”-전체-흐름
μ˜ˆμ™Έκ°€ μ²˜λ¦¬λ˜λŠ” 전체 흐름

μ°Έκ³ 

Windows via C/C++ Fifth Edition, Jeffrey Richter

 

λ°˜μ‘ν˜•