1

I've been debugging a heap corruption exception in one of our applications. It just started happening last month (march 2015) on code that hasn't changed. windbg narrowed it down to some code where we are using pinvoke to invoke a zlib function from c#.

The code snippet is:

public class Info
{

    [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
    private static extern string zlibVersion();


    public static string Version { get { return zlibVersion(); } }
}

It looks like this code is from zlib.net source\contrib\dotzlib\DotZLib\DotZlib.cs which is a dotnet wrapper to zlib.dll.

Question: Any idea why this would cause a heap corruption? Is there a problem with the dotnet pinvoke? I would think a lot of other applications could be using this same wrapper. However I'm not finding others complaining about this on the internet.

Edit 1 - Here's the unmanaged interface from the zlib source (zlib.h):

ZEXTERN const char * ZEXPORT zlibVersion OF((void));
ujjb
  • 53
  • 7

1 Answers1

2

The most likely explanation is that the C string returned by this function was statically allocated. And as such must not be deallocated by the caller, which is what the p/invoke marshaller does with your code. It does this by passing the C string to CoTaskMemFree.

So you need to stop that happening. Do that by marshaling the return value manually.

[DllImport("ZLIB1.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr zlibVersion();

public static string Version 
{
    get 
    { 
        return Marshal.PtrToStringAnsi(zlibVersion());
    } 
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks. This appears to fix the crash in our automated test. I'll let the zlib folks know. – ujjb Apr 01 '15 at 19:53
  • I found this also which has more information. Still not sure why it just now started crashing. The code in question hasn't been changed in many years. http://stackoverflow.com/questions/6300093/why-cant-i-return-a-char-string-from-c-to-c-sharp-in-a-release-build – ujjb Apr 01 '15 at 20:03
  • 1
    OS update could explain a change in behaviour. FWIW, this one is better: http://stackoverflow.com/questions/370079/pinvoke-for-c-function-that-returns-char/370519#370519 but there's no more information than in my answer. That's all there is. string return values are assumed to have been dynamically allocated on the COM heap and are expected to be deallocated by caller. – David Heffernan Apr 01 '15 at 20:06
  • 2
    You can let the zlib folks know, but I'm not clear on what they should do about it. zlib won't be allocating memory unnecessarily for returned strings just because of some odd assumption in C#. – Mark Adler Apr 02 '15 at 02:23
  • 2
    It's not an odd assumption in C# @Mark. The mistake here is by whoever wrote that p/invoke import using C#. zlib is fine. C# is fine. The author of this particular C# wrapper of zlib made a mistake. Whoever wrote that code is who needs to be notified. – David Heffernan Apr 02 '15 at 08:06