使用加密后,在终结器线程中获取“ReleaseHandleFailed”MDA

我在循环中第二次运行此代码后获得了MDA(使用不同的file参数:

 byte[] encryptedData = File.ReadAllBytes(file); // before this line it throws, see exception below long dataOffset; using (var stream = new MemoryStream(encryptedData)) using (var reader = new BinaryReader(stream)) { // ... read header information which is not encrypted } using (var stream = new MemoryStream(encryptedData)) { stream.Seek(dataOffset, SeekOrigin.Begin); using (var aesAlg = new AesCryptoServiceProvider()) using (var decryptor = aesAlg.CreateDecryptor(key, iv)) using (var csDecrypt = new CryptoStream(stream, decryptor, CryptoStreamMode.Read)) using (var reader = new BinaryReader(csDecrypt)) { decrypted = reader.ReadBytes((int)(encryptedData.Length - dataOffset)); } } 

MDA如下:

“Microsoft.Win32.SafeHandles.SafeCapiKeyHandle”类型的SafeHandle或CriticalHandle无法正确释放值为0x000000001BEA9B50的句柄。 这通常表示通过其他方式错误地释放了句柄(例如使用DangerousGetHandle提取句柄并直接关闭它或在其周围构建另一个SafeHandle。)

堆栈跟踪没有太多信息:

mscorlib.dll!System.Runtime.InteropServices.SafeHandle.Dispose(bool disposing)+ 0x10 bytes mscorlib.dll!System.Runtime.InteropServices.SafeHandle.Finalize()+ 0x1a bytes

我怀疑其中一个流或CryptoServiceProvider由于某种原因未发布。 除此之外,代码运行良好,并做到了预期。 MDA在控件到达方法的第一行之前发生。

我怎么能正确地做到这一点? 问题的根本原因是什么?

很明显,终结器线程正在最终确定已经处理好的SafeHandle。 这是AesCryptoServiceProvider.Dispose(bool)方法的实现:

 protected override void Dispose(bool disposing) { try { if (disposing) { if (this.m_key != null) this.m_key.Dispose(); if (this.m_cspHandle != null) this.m_cspHandle.Dispose(); } } finally { base.Dispose(disposing); } } 

三个错误:

  • 处理后,它不会将m_key字段设置为null
  • GC.SuppressFinalize()不会被调用,甚至不会被.NET 3.5中的基类调用
  • SafeCapiKeyHandle类不会使其ReleaseHandle()方法中存储的句柄无效。

所有三个错误的组合足以触发此MDA。 它仍然在.NET 4.0中被窃听,但至少GC.SuppressFinalize由SymmetricAlgorithm.Dispose(bool)调用,因此不会使用终结器。

鼓励看到框架大师搞砸了。 您可以在connect.microsoft.com上报告该问题。 要阻止调试器唠叨这一点,请使用Debug + Exceptions,Managed Debugging Assistants,取消ReleaseHandleFailed。 默认情况下,这个是未被攻击的,这肯定是你第一个注意到这个bug的原因。

我认为第三个错误使这成为一个关键问题顺便说一句,从技术上讲,这个bug可能会导致循环句柄值被关闭。 虽然赔率非常小。 相当具有讽刺意味,因为这是一个安全的句柄类。