heap corruption error when calling SysFreeString() - c#

// --------------------------- C# Code ------------------------------
[DllImport("MarshallStringsWin32.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static void PassStringOut([MarshalAs(UnmanagedType.BStr)] out String str);
[DllImport("MarshallStringsWin32.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static void FreeString([MarshalAs(UnmanagedType.BStr)] String str);
static void Main(string[] args)
{
String str;
PassStringOut(out str);
FreeString(str);
}
// --------------------------- C+ Code ------------------------------
void PassStringOut(__out BSTR* str)
{
const std::string stdStr = "The quick brown fox jumps over the lazy dog";
_bstr_t bstrStr = stdStr.c_str();
*str = bstrStr.copy();
}
void FreeString(BSTR str)
{
SysFreeString(str);
}
The value of 'str' pointer in PassStringOut() and FreeString() are different, and I am getting a heap corruption error when calling SysFreeString(). Should I pass 'str' by reference to FreeString()? If so, what is the syntax I should use in C# and C++?

The marshaling layer will allocate a copy of the string in managed memory. That copy will be freed by the garbage collector. You do not have to SysFreeString a String in C#, and in fact, attempting to do so is a great way to corrupt the heap, as you have discovered.
should I take it that there will be 2 copies performed on the string? The *str = bstrStr.copy(); and then by the marshalling layer?
Let me describe in more detail what is happening here.
Your Main method invokes the unmanaged code, passing the managed address of a local variable of type String. The marshaling layer creates its own storage of suitable size to hold a BSTR and passes a reference to that storage to your unmanaged code.
The unmanaged code allocates a string object that refers to the storage associated with the literal, then allocates a BSTR and makes the first copy of the original string into the heap-allocated BSTR. Then it makes a second copy of that BSTR and fills in the out parameter with a reference to that storage. The bstrStr object goes out of scope and its destructor frees the original BSTR.
The marshaling layer then makes a managed string of the appropriate size, copying the string for a third time. It then frees the BSTR that was passed to it. Control returns to your C# code, which now has a managed string.
That string is passed to FreeString. The marshaling layer allocates a BSTR and for the fourth time makes a copy of the string into the BSTR, which is passed to your unmanaged code. It then frees a BSTR which it does not own and returns. The marshaling layer frees the BSTR that it allocated, corrupting the heap.
The managed heap remains uncorrupted; the managed string will be freed by the garbage collector at a time of the garbage collector's choosing.
Should I pass 'str' by reference to FreeString()?
No. Rather, you should stop writing interop code until you have a thorough and deep understanding of how all aspects of marshalling work.
Marshalling data between managed and unmanaged code is difficult even for experts to get correct. My advice is that you take a large step back and obtain the services of an expert who can teach you how to write interop code safely and correctly, should you need to do so.

This doesn't work the way you think it works. The pinvoke marshaller already released the BSTR automatically. It happened when you called PassStringOut(), the marshaller converted it to a System.String and released the BSTR. This is the normal and necessary protocol for passing BSTRs between native and managed code.
What goes wrong in FreeString() is that a new BSTR got allocated by the pinvoke marshaller. And it got released twice. First by your native code, again by the pinvoke marshaller. Kaboom from the debug heap that is used when you run your code with a debugger attached.
You are just helping too much, don't call FreeString().
You can get the pinvoke marshaller to handle ANSI strings for you, it is in fact the default behavior since they are so common in legacy C code. Your C++ function could look like this:
extern "C" __declspec(dllexport)
void __stdcall PassStringOut(char* buffer, size_t bufferLen)
{
const std::string stdStr = "The quick brown fox jumps over the lazy dog";
strcpy_s(buffer, bufferLen, stdStr.c_str());
}
With matching C# code:
class Program {
static void Main(string[] args) {
var buffer = new StringBuilder(666);
PassStringOut(buffer, buffer.Capacity);
Console.WriteLine(buffer.ToString());
Console.ReadLine();
}
[DllImport("Example.dll")]
private static extern bool PassStringOut(StringBuilder buffer, int capacity);
}
Having to guess the proper size of the buffer is however the fugly detail.

Related

C# Interop - Releasing memory allocated in unmanaged code

I'm calling the following VC++ method
__declspec(dllexport) unsigned char* Get_Version_String()
from C# as follows:
internal static class NativeMethods
{
[DllImport("my.dll"),
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true,
CallingConvention = CallingConvention.Cdecl)]
internal static extern string Get_Version_String();
}
The above code is in a library which targets .NET 3.5. When I call this from a 3.5 assembly, it works fine; when calling it from a 4.5 assembly, however, it results in
0xC0000374: A heap has been corrupted
After reading this question, I changed my method calls as follows:
[DllImport("my.dll",
EntryPoint = "Get_Version_String",
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Get_Version_String_PInvoke();
internal static string Get_Version_String()
{
IntPtr ptr = Get_Version_String_PInvoke();
string versionString = Marshal.PtrToStringAnsi(ptr);
return versionString;
}
This works as expected, but the answer from Hans Passant comes with a warning:
The workaround you found is the correct one, the marshaller isn't going to try to release the memory for an IntPtr. Do note that this will only actually come to a good end if the C code returns a const char* that doesn't need to be released. You have a permanent memory leak if that's not the case.
Since the C++ method does not return const, I'm going on the assumption that the workaround for my specific function will result in a memory leak.
I cannot change the original method so I found this other question which discusses how to free memory from manged code. However, calling either Marshal.FreeHGlobal(ptr) or Marshal.FreeCoTaskMem(ptr) also throw 0xC0000374: A heap has been corrupted.
Can anyone
a) confirm that such a method will indeed suffer from a memory leak, and
b) if so, suggest how to free the memory from the pointer in managed code?
The C++ method body is, simplified, as follows:
unsigned char versionString[50];
__declspec(dllexport) unsigned char* Get_Version_String()
{
strcpy((char *) versionString, "Key1:[xx],Key2:[xx],Key3:[xx],Key4:[xx]");
// string manipulation
return versionString;
}
Thanks in advance, and sorry if this is trivial; I'm neither a C++ nor an Interop expert.
Can anyone confirm that such a method will indeed suffer from a memory leak
Only you can do that, the missing const keyword is not a guarantee that the native code does not in fact return a literal. Pervasive mistake in C code btw. Write a little test program that calls the function a hundred million times. If you don't see the memory usage explode with Task Manager then you don't have a problem.
if so, suggest how to free the memory from the pointer in managed code?
You just can't, it must be the native code itself that calls free(). So that it uses the correct heap, the one that was created by the C runtime library used by that code. Underlying winapi call is HeapCreate(), you don't have the heap handle. Technically it is discoverable with GetProcessHeaps() but you just don't know which one is the "right" one. Starting with VS2012, the CRT uses GetProcessHeap() instead of HeapCreate(), now Marshal.FreeHGlobal() can work. But you know that this code doesn't, you'll have to ask the author or vendor for an update. As long as you do that, ask him for a more usable flavor of this function, it should take a char* as an argument instead.
A more constructive approach is to just take the memory leak in stride. Simply call the function once, the version number is not going to change while your program is running. So store it in a static variable. Losing ~80 bytes of address space is not a problem you can ever notice, the OS automatically cleans up when your program terminates.

Free C# Automatically Marshalled Data using MarashalAs Attribute

CLR can marshal managed types into unmanaged c/c++ types using marshal as attrubte
what I need is that what is the proper method to free this allocated memory.. for example::
in C/C++ code
char* dummy(char* text){
//do some thing
return text;//dummy way to return it to the caller to free it.
}
and in C#
[DllImport("test.dll",CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr dummy([MarshalAs(UnmanagedType.LPStr)] string text);
and finally the test
C# Test
IntPtr marshaledData=dummy("any text");
//what is the proper way to free this memory location

Managing unmanaged string across C++ / C# boundary with P/Invoke

I have the following struct declared (C++):
struct NativeOperationResult {
const INTEROP_BOOL Success; // INTEROP_BOOL = char
const char16_t* const ErrorMessage;
NativeOperationResult(const NativeOperationResult& c);
/* various constructors, omitted for brevity */
};
Now, I have an exported function definition elsewhere:
extern "C" __declspec(dllexport) NativeOperationResult ReturnFailureWithMessage() {
return { INTEROP_BOOL_FALSE, "Test" };
}
My expectation is to be calling ReturnFailureWithMessage (a test method in case you were wondering) from C# via P/Invoke. In the NativeOperationResult constructor, it takes a copy of "Test" and puts it in ErrorMessage.
The NativeOperationResult has ownership of the char16_t* so I need to delete it when the struct is destroyed. That's no problem, but I don't want to delete the memory before the .NET CLR has a chance to copy the string in to the managed heap.
Frankly I'm a bit fuzzy on where to delete that memory. What I think is that the C++ compiler will make a copy of my struct (or just move it) and then the CLR will use that copy... Which means I should delete the native memory from .NET with Marshal.FreeHGlobal.
Is that correct?
No, that is not correct. You need to differentiate between two cases:
1) You didn't do any allocations on C++ side. This is the case you are talking about right now.
2) You did do allocations on C++ side, you need to take care of deallocation.
Thus to answer your question: no, your example does not need any "deletion" of memory, since no-one has allocated the memory explictly.
Second case is a bit trickier. If you do memory allocations on C++ side with new char16_t[blah], you need to release the memory with delete[] nativeOperationResult.ErrorMessage. This is not possible to do on C# side. The memory can be allocated using different allocators(such as; malloc, new) and C# does not know how to deal with these pointers.
You need to add a new flag to NativeOperationResult, such as DeletionRequired, and export new function from unmanaged side: FreeNativeOperationResultIfNeeded(..). There is longer discussion here.
You can avoid all this non-sense with C++ strings. They work magically, and no deletion is required.
struct NativeOperationResult {
const INTEROP_BOOL Success; // INTEROP_BOOL = char
const string const ErrorMessage;
NativeOperationResult(const NativeOperationResult& c);
/* various constructors, omitted for brevity */
};
Instead of returning NativeOperationResult, you can make it an out parameter and expect the calling method to pass it the right amount of memory. That way the .Net can allocate memory and then clean it up after the pinvoke is done. But you will have to figure out a way to inform .Net the amount of memory it is expected to allocate.
extern "C" __declspec(dllexport) void ReturnFailureWithMessage(NativeOperationResult* result)

Receiving char* from C++ method, converting to managed string, then deallocating memory

I have a third party unmanaged C++ dll that I need to call from C#. The C++ function returns a char*. I've figured out how to convert that to a managed string in C#. But I don't know if I need to deallocate the memory. The following code works except that Marshal.FreeHGlobal(p) throws "The handle is invalid.". So do I need to deallocate the memory, and if so, how?
[DllImport("abc.dll", EntryPoint = "?GetVersion#ABC##QEAAPEADXZ", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern unsafe char* GetVersionRaw();
public static unsafe string GetVersion()
{
char* x = Abc.GetVersionRaw(); // call the function in the unmanaged DLL
IntPtr p = new IntPtr(x);
string s = Marshal.PtrToStringAnsi(p);
Marshal.FreeHGlobal(p);
return s;
}
It is impossible to say in general how to free an arbitrary pointer returned from a C++ function. There are many ways the pointer could have been produced (new, malloc, VirtualAlloc when you're on Windows, etc). There is no way to determine by inspection which one the pointer came from, and using the wrong deallocation function is an error (which may crash your process). Also, even if you know which function to call, your code may be linked against a different version of the language runtime library - so you might be correctly calling free or delete, but an incompatible version.
Normal procedure is for libraries that perform allocation to provide a corresponding deallocation function that frees the allocated memory appropriately. If the library you're using doesn't have this, you'll just have to try what they've told you and follow up if it doesn't work.

Marshal C++ "char**" in C#

I'm calling C# method from C++ and passing char** as argument. It has to be char** because I need to return value through parameter.
C# code:
[ExportDll("test", System.Runtime.InteropServices.CallingConvention.StdCall)]
public static int test([MarshalAs(UnmanagedType.AnsiBStr)] ref string p)
{
Console.WriteLine(p);
}
C++ code to invoke function:
typedef int (__stdcall *MYPROC)(char **);
VOID main(VOID)
{
HINSTANCE hinstLib;
MYPROC MyProc;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
hinstLib = LoadLibrary(TEXT("mydll.dll"));
if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "test");
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
char s1[] = "test";
char *s2 = s1;
char **s3 = &s2;
(MyProc) (s3);
cout << s3;
}
fFreeResult = FreeLibrary(hinstLib);
}
}
It's simple to pass char* (remove ref in c#, and use char* in c++), but when trying to pass char** i get a runtime error on line where I call the function :(
in c#, Console.WriteLine prints out correct value, but after that, I get an error:
Windows has triggered a breakpoint in COMDynamicLoad.exe.
This may be due to a corruption of the heap, which indicates a bug in COMDynamicLoad.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while COMDynamicLoad.exe has focus.
The output window may have more diagnostic information.
How should I do this?
You declare ref UnmanagedType.AnsiBStr but you expect a char**. This cannot work, since a ref to a BSTR is not a char**. See Default Marshaling for Strings for examples of marshaling declarations. These are possible declarations for an input-output string:
PassStringRef2([in, out] BSTR *s);
PassStringRef3([in, out] LPStr *s);
PassStringRef4([in, out] LPWStr *s);
and the equivalent C# marshaling declarations are:
PassStringRef2([MarshalAs(UnmanagedType.BStr)]ref String s);
PassStringRef3([MarshalAs(UnmanagedType.LPStr)]ref String s);
PassStringRef4([MarshalAs(UnmanagedType.LPWStr)]ref String s);
Your char** declaration is the equivalent of LPStr *s, so the correct marshaling is [MarshalAs(UnmanagedType.LPStr)]ref String s. But a better option is to use BSTR because of the explicit length declaration, and manipulate it in C++ with the BSTR helpers.
This is likely because you took a char* pointing to a string literal- which is bad because modifying that memory is undefined behaviour.
Would this work?
public static int test([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] p)
In many cases and as seems to be the situation here (see accepted answer by Remus Rusanu), using the proper marshaling attributes in the API declarations is all that is needed to have the interop "glue" on both ends of the interface start "playing nice with one another" and result in...
the proper data values being sent/delivered [good!]
Windows not triggering automatic breakpoint upon various suspected ... corruption of the heap ... [better! ;-)]
I am adding this answer, 5 months after the original post, because this question and its responses were very useful in fixing a recent interop bug of mine, but failed to mention directly information about the very plausible cause of many interop issues, namely:
Mismatch in the Memory Ownership conventions
(and/or in the memory allocation and freeing methods).
The January 2008 article on MSDN Magazine titled Marshaling between Managed and Unmanaged Code provided me with the info I needed in regards to memory ownership conventions. Indeed this article provides a complete overview of the marshaling process. It covers in specific details and examples the issues of
[InAttribute] and [OutAttribute] aka [In] and [Out]
Keywords Out and Ref and passing by reference
Return values
StringBuilder and marshaling
Copying and pinning
(Pinning = optiimization by CLR when it deems it safe to lock data area in the CLR heap and pass corresponding pointers to unmanaged code)
Memory Ownership:
No change allowed vs. In-place change vs. Reference change
Also, on the need of using CoTaskMemFree() and CoTaskMemAlloc() to free or allocate memory respectively received from or sent to the Managed code.
Reverse P/Invoke and delegate lifetime
P/Invoke Interop Assistant
This article is very useful because it gathers in a single document and in an accessible fashion information otherwise disseminated across dozen of technically authoritative but dry [and oft' confusing] reference documents (cf. the old but on-point joke about Microsoft's documentation at large).
In short, it makes it a good primer or refresher for casual implementers of interop solutions.

Categories

Resources