SafeHandle 및 중요한 종료

.NET Framework 2.0 이전 버전에서는 모든 운영 체제 핸들을 관리되는 래퍼 개체 IntPtr에만 캡슐화할 수 있었습니다. 이는 네이티브 코드와 상호 작용하는 데는 편리한 방법이었지만 예기치 않은 스레드 중단이나 스택 오버플로와 같은 비동기 예외로 인해 핸들이 누수될 수 있었습니다. 이러한 비동기 예외는 운영 체제 리소스를 정리하는 데 방해가 되며 프로그램의 거의 모든 위치에서 발생할 수 있습니다. Microsoft SQL Server와 같이 관리 코드를 실행하는 호스트를 사용하는 응용 프로그램에서 이러한 비동기 예외가 발생하기 쉽습니다.

경우에 따라 플랫폼 호출 서비스에 대한 호출 내에서 메서드를 실행하는 동안 가비지 수집을 통해 종료 가능한 개체가 회수될 수 있습니다. 플랫폼 호출 서비스를 호출할 때 전달된 핸들을 종료자가 해제하면 핸들이 손상될 수 있습니다. 파일을 읽을 때와 같이 플랫폼 호출 서비스를 호출하는 동안 메서드가 차단된 상태에서 핸들이 회수될 수도 있습니다.

보다 중요한 것은 Windows에서는 핸들을 적극적으로 재생하므로 핸들이 재생되어 중요한 데이터가 들어 있는 다른 리소스를 가리키게 될 수 있다는 점입니다. 재생 공격이라고 하는 이런 유형의 공격을 받으면 데이터가 손상되고 보안상 위험해질 수 있습니다.

.NET Framework 2.0부터는 SafeHandle 클래스가 플랫폼 호출과 통합되어 이러한 여러 가지 개체 수명 문제를 단순화하므로 운영 체제 리소스가 누수되지 않습니다. SafeHandle 클래스는 핸들을 중단하지 않고 할당 및 해제함으로써 개체 수명 문제를 해결합니다. 이 클래스에 들어 있는 중요한 종료자는 AppDomain이 언로드될 때 실행되어 핸들이 닫히도록 합니다. 이는 플랫폼 호출 서비스에 대한 호출이 손상된 상태인 경우에도 해당됩니다.

SafeHandleCriticalFinalizerObject에서 상속되므로 중요하지 않은 종료자가 모두 호출된 후에 중요한 종료자가 호출됩니다. 종료자는 동일한 가비지 수집이 진행되는 동안 더 이상 라이브 상태가 아닌 개체에 대해 호출됩니다. 예를 들어, FileStream 개체는 일반적인 종료자를 실행하여 버퍼링된 기존 데이터를 플러시할 수 있으며 이때 핸들이 누수되거나 재생될 위험은 없습니다. 이와 같이 중요한 종료자와 중요하지 않은 종료자 간에 엄격하지 않은 순서를 정한 것은 일반적인 경우에 적용하기 위한 것이 아닙니다. 이는 주로 기존 라이브러리에서 해당 의미 체계를 변경하지 않고도 SafeHandle을 사용할 수 있도록 함으로써 기존 라이브러리의 마이그레이션을 용이하게 하기 위한 것입니다. 또한 중요한 종료자와 종료자가 호출하는 SafeHandle.ReleaseHandle() 메서드 등의 모든 항목은 제약이 있는 실행 영역에 있어야 합니다. 이로써 종료자의 호출 그래프 내에서 작성할 수 있는 코드에 대한 제약 조건이 적용됩니다.

.NET Framework 버전 2.0부터는 플랫폼 호출 작업 시 SafeHandle로 캡슐화된 핸들의 참조 횟수가 자동으로 늘어났다가 작업이 완료되면 줄어듭니다. 따라서 핸들이 예기치 않게 재생되거나 닫히지 않게 됩니다.

SafeHandle 개체를 생성할 때 내부 핸들의 소유권을 지정할 수 있습니다. 이렇게 하면 SafeHandle 개체가 삭제된 후에 해당 개체에서 핸들을 해제할지 여부를 제어할 수 있습니다. 이는 핸들의 수명 요구 사항이 일반적이지 않거나 다른 사용자에 의해 수명이 제어되는 핸들을 사용할 경우에 유용합니다.

SafeHandle 클래스

System.Runtime.InteropServices 네임스페이스에서 SafeHandle 클래스는 운영 체제 핸들에 대한 추상 래퍼 클래스입니다. 이 클래스로부터 파생은 어렵습니다. 대신 Microsoft.Win32.SafeHandles 네임스페이스에서 다음에 대해 SafeHandle을 제공하는 파생된 클래스를 사용하십시오.

  • 파일 및 파이프

  • 메모리 뷰

  • 암호화 구문

  • 레지스트리 키

  • 대기 핸들

참고 항목

참조

SafeHandle

CriticalHandle

CriticalFinalizerObject