我在循环中第二次运行此代码后获得了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));
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
三个错误:
所有三个错误的组合足以触发此MDA.它仍然在.NET 4.0中被窃听,但至少GC.SuppressFinalize由SymmetricAlgorithm.Dispose(bool)调用,因此不会使用终结器.
鼓励看到框架大师搞砸了.您可以在connect.microsoft.com上报告问题.要阻止调试器唠叨这一点,请使用Debug + Exceptions,Managed Debugging Assistants,取消ReleaseHandleFailed.默认情况下,这个是未被攻击的,这肯定是你第一个注意到这个bug的原因.
我认为第三个错误使这成为一个关键问题顺便说一句,从技术上讲,这个错误可能会导致循环句柄值被关闭.虽然赔率非常小.相当讽刺的是,鉴于这是一个安全的句柄类.