Examples

The following code example creates a custom safe handle for an operating system file handle, deriving from SafeHandleZeroOrMinusOneIsInvalid. It reads bytes from a file and displays their hexadecimal values. It also contains a fault testing harness that causes the thread to abort, but the handle value is freed. When using an IntPtr to represent handles, the handle is occasionally leaked due to the asynchronous thread abort.

You will need a text file in the same folder as the compiled application. Assuming that you name the application "HexViewer", the command line usage is:

HexViewer <filename> -Fault

Optionally specify -Fault to intentionally attempt to leak the handle by aborting the thread in a certain window. Use the Windows Perfmon.exe tool to monitor handle counts while injecting faults.

Remarks

The SafeHandle class provides critical finalization of handle resources, preventing handles from being reclaimed prematurely by garbage collection and from being recycled by Windows to reference unintended unmanaged objects.

Why SafeHandle?

Before the .NET Framework version 2.0, all operating system handles could only be encapsulated in the IntPtr managed wrapper object. While this was a convenient way to interoperate with native code, handles could be leaked by asynchronous exceptions, such as a thread aborting unexpectedly or a stack overflow. These asynchronous exceptions are an obstacle to cleaning up operating system resources, and they can occur almost anywhere in your app.

Although overrides to the Object.Finalize method allow cleanup of unmanaged resources when an object is being garbage collected, in some circumstances, finalizable objects can be reclaimed by garbage collection while executing a method within a platform invoke call. If a finalizer frees the handle passed to that platform invoke call, it could lead to handle corruption. The handle could also be reclaimed while your method is blocked during a platform invoke call, such as while reading a file.

More critically, because Windows aggressively recycles handles, a handle could be recycled and point to another resource that might contain sensitive data. This is known as a recycle attack and can potentially corrupt data and be a security threat.

What SafeHandle does

The SafeHandle class simplifies several of these object lifetime issues, and is integrated with platform invoke so that operating system resources are not leaked. The SafeHandle class resolves object lifetime issues by assigning and releasing handles without interruption. It contains a critical finalizer that ensures that the handle is closed and is guaranteed to run during unexpected AppDomain unloads, even in cases when the platform invoke call is assumed to be in a corrupted state.

Because SafeHandle inherits from CriticalFinalizerObject, all the noncritical finalizers are called before any of the critical finalizers. The finalizers are called on objects that are no longer live during the same garbage collection pass. For example, a FileStream object can run a normal finalizer to flush out existing buffered data without the risk of the handle being leaked or recycled. This very weak ordering between critical and noncritical finalizers is not intended for general use. It exists primarily to assist in the migration of existing libraries by allowing those libraries to use SafeHandle without altering their semantics. Additionally, the critical finalizer and anything it calls, such as the SafeHandle.ReleaseHandle() method, must be in a constrained execution region. This imposes constraints on what code can be written within the finalizer's call graph.

Platform invoke operations automatically increment the reference count of handles encapsulated by a SafeHandle and decrement them upon completion. This ensures that the handle will not be recycled or closed unexpectedly.

You can specify ownership of the underlying handle when constructing SafeHandle objects by supplying a value to the ownsHandle argument in the SafeHandle class constructor. This controls whether the SafeHandle object will release the handle after the object has been disposed. This is useful for handles with peculiar lifetime requirements or for consuming a handle whose lifetime is controlled by someone else.

Classes derived from SafeHandle

SafeHandle is an abstract wrapper class for operating system handles. Deriving from this class is difficult. Instead, use the derived classes in the Microsoft.Win32.SafeHandles namespace that provide safe handles for the following:

Notes to Implementers

To create a class derived from SafeHandle, you must know how to create and free an operating system handle. This process is different for different handle types because some use the CloseHandle function, while others use more specific functions such as UnmapViewOfFile or FindClose. For this reason, you must create a derived class of SafeHandle for each operating system handle type that you want to wrap in a safe handle.

You should also provide a parameterless constructor that calls the base constructor with a value that represent an invalid handle value, and a Boolean value indicating whether the native handle is owned by the SafeHandle and consequently should be freed when that SafeHandle has been disposed.