安全句柄和紧急终结

在 .NET Framework 2.0 版之前,所有操作系统句柄都可以仅在 IntPtr 托管包装对象中封装。 虽然这样可以方便地与本机代码交互操作,但是句柄可能会由异步异常泄漏,如线程意外中止或堆栈溢出。 这些异步异常会在程序中的几乎任何地方出现,是清理操作系统资源的障碍。 这些异常容易发生在使用运行托管代码(如 Microsoft SQL Server)的主机的应用程序中。

在某些情况下,在平台调用中执行方法时,垃圾回收操作可能对可终结对象进行回收。 如果终结器释放传递给该平台调用的句柄,可能导致句柄损坏。 当您的方法在平台调用期间被阻止时(如读取文件时),句柄也可能被回收。

更严重的是,由于 Windows 积极回收句柄,因此句柄可能被回收后指向另一个可能包含敏感数据的资源。 这称为回收攻击,可能损坏数据,成为安全威胁。

从 .NET Framework 2.0 开始,SafeHandle 类简化了几个对象生存期问题,并与平台调用集成,以使操作系统资源不会泄漏。 SafeHandle 类通过无中断地分配和释放句柄来解决对象生存期问题。 它包含关键终结器,确保句柄关闭并保证在 AppDomain 卸载期间运行,即使当平台调用假定为损坏状态时,也是如此。

由于 SafeHandle 是从 CriticalFinalizerObject 继承的,因此,在任何关键终结器之前调用所有非关键终结器。 将对在同一垃圾回收传递期间不再活动的对象调用终结器。 例如,FileStream 对象可以运行常规终结器来刷新现有缓冲数据,而没有句柄被泄漏或回收的风险。 关键终结器与非关键终结器之间的这一弱顺序不供常规使用。 它主要是通过允许现有库不更改语义即可使用 SafeHandle 来帮助现有库进行迁移。 另外,关键终结器和它所调用的任何内容(如 SafeHandle.ReleaseHandle() 方法)都必须在一个受约束执行区域内。 这样便对在终结器调用关系图中可以写哪些代码设置了约束。

从 .NET Framework 2.0 版开始,平台调用操作自动递增由 SafeHandle 封装的句柄引用计数,并在完成时递减。 这样可以确保句柄不会被意外回收或关闭。

当构造 SafeHandle 对象时,您可以指定基础句柄的所属权。 可以控制 SafeHandle 对象被释放后,它是否释放句柄。 对于具有特殊生存期要求的句柄或对于所消耗的句柄的生存期被其他人控制的情况,这很有用。

安全句柄类

System.Runtime.InteropServices 命名空间中的 SafeHandle 类是操作系统句柄的抽象包装类。 从此类派生比较困难。 但可以使用 Microsoft.Win32.SafeHandles 命名空间中可提供以下项的安全句柄的派生类。

  • 文件和管道。

  • 内存视图。

  • 加密结构。

  • 注册表项。

  • 等待句柄。

请参见

参考

SafeHandle

CriticalHandle

CriticalFinalizerObject