哪些“IntPtr”风格是“SafeHandle”的候选者
Posted
技术标签:
【中文标题】哪些“IntPtr”风格是“SafeHandle”的候选者【英文标题】:Which `IntPtr` flavors are candidates for a `SafeHandle` 【发布时间】:2017-06-12 16:49:10 【问题描述】:我得到一个 CA2006 ("Review usage of ... (a 'IntPtr' instance) to determine whether it should be replaced with a SafeHandle or CriticalHandle
") 用于从 ConvertStringSecurityDescriptorToSecurityDescriptor
返回的 IntPtr
,我知道这是一个可以用 FreeLocal
释放的安全描述符。我只是简单地使用它,可能不会泄漏所涉及的内存。据我所知,没有关联内核句柄。
有很多 SafeHandle
子类,并且在包装对象的生命周期结束时,它们似乎都没有调用 FreeLocal
。但是,我找不到任何关于哪些IntPtr
实例(例如,由 Win32 API 返回)由SafeHandle
有效管理而哪些不是的确切信息。
我应该只取消 CA 警告吗?
更重要的是,如何确定我将遇到的下一个IntPtr
用法相同?
(将SafeHandle
子类映射到最终将释放句柄的函数的表会很棒。)
【问题讨论】:
没有错,只是严重的过度杀戮。当你编写一个终结器来释放资源时,你会考虑它。 @HansPassant - 这有帮助,但终结者本身就是灰色地带的野兽。它们是将资源的生命周期与另一个随机资源(托管堆的一小块)联系起来。他们充其量只是第二层防御,从来没有靠自己可靠地完成任何事情。 【参考方案1】:如果您的问题是“是否已经有一个 SafeHandle
子类调用 LocalFree
来释放它的句柄”,那么是的,有 - 它是 SafeLocalAllocHandle
。该类是internal
,因此它不向公众提供,但如果您想重新创建它,代码是显而易见的。如果您的问题是“我应该使用这样的课程吗”,那么这有点像判断题。 CA2006
和 SafeHandle
文档解释了设计原理:SafeHandle
避免了多线程场景中的句柄回收问题,并特别支持 P/Invokes 以确保在使用非托管代码之前不会意外释放句柄。
IntPtr
何时是可以被SafeHandle
包裹的句柄?您无法从IntPtr
中分辨出来,您必须知道返回IntPtr
的函数是什么。它将记录您是否正在处理句柄,如果是,则在完成处理后应如何关闭句柄(经常,但绝不总是,CloseHandle
)。如果你只有一个 P/Invoke 签名,那么从技术上讲,你什么都没有。特别是,如果它是句柄,则无法确定应该调用什么函数来释放句柄。 IntPtr
也可用于编组PVOID
或SIZE_T
或P<some_struct>
(尽管out
或ref
参数更自然)或任何其他应该是指针大小的类型。
任何超出单个函数(尤其是存储在字段中的函数)的句柄作为IntPtr
都非常适合SafeHandle
包装器,就像同时使用多个IntPtr
s 一样时间(以防止意外混淆不兼容的句柄)。对于不涉及多线程并且不会让句柄超出其范围的简单一次性,try .. finally
块可能就足够了。如果您愿意,为了一致性起见,所有内容都可以包装在SafeHandle
中(或明确记录您正在处理的对象类型),但这并不一定会带来更好的结果。句柄回收是一个严重的问题,但这里不是一个问题,因为句柄是本地内存,可靠性不是问题,因为任何严重到足以绕过finally
块的问题也严重到足以导致小内存泄漏没有问题。
您的特定场景(将 SDDL 解析为安全描述符)已经以 RawSecurityDescriptor
的形式在框架中实现,您应该考虑使用它来支持重新发明***(和/或实现您自己的 SecurityDescriptor
子类如果 System.Security.AccessControl
中的现有类尚未涵盖它。对于它的价值,RawSecurityDescriptor
也 P/Invokes 到 ConvertStringSecurityDescriptorToSecurityDescriptorW
并且不会打扰 SafeHandle
。框架代码不一定被视为做什么的好例子(大量代码违反了官方指南),但它是一些东西。
【讨论】:
以上是关于哪些“IntPtr”风格是“SafeHandle”的候选者的主要内容,如果未能解决你的问题,请参考以下文章
SafeHandle 中 invalidHandleValue 的作用是啥?
无法将 ReleaseHandle 中的 SafeHandle 实例传递给本机方法