error: a SafeHandle or CriticalHandle of type ZLibStreamHandle failed to properly release

2.3k Views Asked by At

I haven't worked much with streams, so I assume there's a coding error here on my part, somewhere.

   public static SqlBytes Compress(SqlBytes input)
    {
        byte[] data = (byte[])input.Value;
        using (MemoryStream memstream = new MemoryStream(data))
        {

            using (GZipStream zipped = new GZipStream(memstream, CompressionMode.Compress))
            {
                using (MemoryStream output = new MemoryStream()) 
                {
                    zipped.CopyTo(output);
                    return new SqlBytes(output.ToArray());
                }

            }

        }
    }

Here's the error in SQL Server 2012 CLR:

Msg 10323, Level 16, State 49, Line 1
Invalid user code has been identified by .Net Framework Managed Debug Assistant 'releaseHandleFailed':
A SafeHandle or CriticalHandle of type 'ZLibStreamHandle' failed to properly release the handle with value 0x0000000000000000. This usually indicates that the handle was released incorrectly via another means (such as extracting the handle using DangerousGetHandle and closing it directly or building another SafeHandle around it.)
   at System.Runtime.InteropServices.SafeHandle.InternalDispose()
   at System.IO.Compression.DeflaterZLib.Dispose(Boolean disposing)
   at System.IO.Compression.DeflateStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.IO.Compression.GZipStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at UserDefinedFunctions.Compress(SqlBytes input)
   at SQLCLR_Eval(IntPtr , IntPtr , IntPtr )
2

There are 2 best solutions below

1
On

identified by .Net Framework Managed Debug Assistant

This is not an exception, just a notification from an MDA (Managed Debugging Assistant). Little bits of codes integrated in the CLR that check for common runtime mishaps. The kind that are hard to diagnose without the help of a hard exception. You only get an MDA notification when you use a debugger. And only when the MDA is enabled, most are not.

'releaseHandleFailed'

The MDA that speaks up is one that checks that a SafeHandle is being used properly. In this specific case it is the ZLibStreamHandle class. Actual de/compression is done by Zlib, an open source library that is written in native code. SafeHandles are commonly used to manage unmanaged resources, they ensure that such a resource is released with a critical finalizer.

What is notable about the releaseHandleFailed MDA is that it is normally turned off. It should be turned on by programmers that write SafeHandle classes, like the Microsoft programmer that wrote ZLibStreamHandle. So while the bug behind this notification might well be commonly encountered, just about nobody ever sees it. Bugs that are never diagnosed never get fixed.

failed to properly release the handle with value 0x0000000000000000

That tells you that the MDA warning is entirely benign. No actual unmanaged resource is getting improperly released and nothing can go wrong, the underlying handle is null. Your program will keep happily motoring on when you press F5 to continue running. As well as any unit test that validated the changes in the 4.5 framework, MDAs are not active in unit tests.


Nevertheless, something did go wrong, the ZLibStreamHandle object should not have been created for a null handle. I see no obvious way how this could have been fumbled in the class itself. And of course the original Microsoft developer didn't see it either :) This MDA is normally triggered by the finalizer. Not the case here, the using statement (aka Dispose() call) triggered it. That's unusual, I suspect that you got this MDA before you got an exception that told you that something went belly up in the native code. Happens because the using statement generates a finally block that executes before the exception is reported. If that's accurate then pressing F5 should reveal the true problem.

There isn't otherwise anything you can do about the bug in the framework code. Other than reporting it so Microsoft can fix it, use connect.microsoft.com to tell them about it.

And turn off the MDA so you can happily ignore it like everybody else does. Debug > Exceptions > Managed Debugging Assistants > untick ReleaseHandleFailed. If you have them all ticked, the most typical way in which MDAs are enabled by accident, then reset the checkbox of the parent.

0
On

In my case, it was just that the database had empty string in a column whose data was compressed. And the issue arises when you zip/unzip empty strings using SQL 2012 only. It isn't seen in SQL 2008/2008R2. Hope this helps.