Getting "ReleaseHandleFailed" MDA in the finalizer stream after using cryptography

I get MDA after running this code a second time in a loop (with another file parameter:

 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:

A SafeHandle or CriticalHandle of type "Microsoft.Win32.SafeHandles.SafeCapiKeyHandle" failed to correctly issue a handle with a value of 0x000000001BEA9B50. This usually indicates that the handle was not released correctly using another tool (for example, retrieving a handle using a DangerousGetHandle and closing it directly or creating another SafeHandle around it.)

The column is not too informative:

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

I suspect that one of the threads or CryptoServiceProvider for some reason is not released. Other than that, the code works just fine and does what is expected. MDA occurs before the control reaches the first line of the method.

How can I do it right? What is the root cause of the problem?

+4
source share
1 answer

Clearly, the finalizer thread completes the installation of SafeHandle, which is already located. This is the implementation of the AesCryptoServiceProvider.Dispose (bool) method:

 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); } } 

Three errors:

  • It does not set the m_key field to null after deleting it
  • GC.SuppressFinalize () is not called, even by a base class in .NET 3.5
  • The SafeCapiKeyHandle class does not cancel the stored handle in the ReleaseHandle () method.

The combination of all three errors is enough to run this MDA. It is still bugged in .NET 4.0, but at least GC.SuppressFinalize is called by SymmetricAlgorithm.Dispose (bool), so the finalizer will not be used.

Inspiring the frame masters to screw. You can report this problem on connect.microsoft.com. To stop the debugger from scuffling, you use Debug + Exceptions, Managed Debugging Assistants, untick ReleaseHandleFailed about this. By default, this person will not be knocked over, probably the reason you first noticed this error.

I think that the third error makes this problem critical; it is technically possible for this error to close the return descriptor value. However, the chances are very small. Pretty ironic considering this is a safe class of descriptors.

+7
source

All Articles