Question

I have a project in C# which uses an unmanaged C++ static library. I am getting a weird bug when C# gets back a string from the unmanaged code. The program crashes and VS tells me of possible heap corruption. The string is a field in an object in the unmanaged code - so it's not a local variable problem. What's weird is that the crash happens always when in debug mode, but only in some very specific cases when actually running the program. Furthermore, although the debug crash is reproducible on all computers, the runtime crash only happens on some computers.

I should note that I have many functions exported from unmanaged code, and none of them cause a problem except this function and another one that does almost the same thing (GetBlockInfo).

Here is the line of code that causes the crash:

string info = CppToCsharpAdapter.GetFileInfo(myHashFilePointer);

CppToCsharpAdapter is my managed/unmanaged code adapter. The CppToCsharpAdapter.GetFileInfo call caries out a call to the GetFileInfo function in my unmanaged code.

Here is the export function in .cpp:

__declspec(dllexport)   const   char* __stdcall  GetFileInfo(HashFile* THIS)
{
      return THIS->GetFileInfo().c_str();   
}

Here is the GetFileInfo function in unmanaged code:

string& GetFileInfo()
{
    try
    {
        LogicalHeaderBlock *infoBlock = LogicalFHBuffer;
        stringstream infoString;
        infoString<<infoBlock->getHashFuncID()<<endl;

             // many more lines//

        fileInfo = infoString.str();
        return fileInfo;

    }
    catch(exception &e)
    { throw e; }
}

Here is the call stack leading up to the crash:

ntdll.dll!770a04e4()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
ntdll.dll!77062a2a()    
ntdll.dll!770a1b71()    
oleaut32.dll!75c43e59()     
[Managed to Native Transition]  
mscorlib.dll!System.StubHelpers.AnsiBSTRMarshaler.ClearNative(System.IntPtr pNative) + 0x45 bytes   
FMS_adapter.dll!FMS_adapter.HashFile.GetFileInfo() Line 249 + 0xb bytes C#

EDIT: Updated the call stack, now I get the line [Managed to Native Transition] which clearly seems to indicate that the problem is there.

Any help will be greatly appreciated. Thanks in advance.

EDIT: I ended up solving the problem by having the C# CppToCsharpAdapter.GetFileInfo() function return an IntPtr, and then converting that to a string within C#.

Was it helpful?

Solution

The problem lies in your P/Invoke definition of CppToCsharpAdapter.GetFileInfo, which you did not include with your question. At a minimum, it needs the following attribute added:

[return: MarshalAs(UnmanagedType.LPStr)]

If you omit this attribute, the P/Invoke layer will assume the returned string is represented in code by a BSTR, but you are actually using a null-terminated ANSI string. This link has more information:

Default Marshaling for Strings: Strings Used in Platform Invoke

OTHER TIPS

Your DLL-exported GetFileInfo() function returns a raw const char*, but I'm not sure this is a correct type for managed code (unless you use a proper P/Invoke signature...).

Have you considered returning a BSTR instead? BSTR is a typical COM string, and I think .NET understands COM very well, so it can also automatically free the COM-allocated string returned by native code.

__declspec(dllexport) BSTR __stdcall GetFileInfo(....)
{
    ....

    // Assume that "nativeString" is "const char*".

    // We first convert from ANSI/MBCS to Unicode:
    // (CA2W is a conversion helper defined in <atlconv.h>)
    CA2W unicodeNativeString( nativeString );

    // ...and then we return a BSTR built from it:
    return ::SysAllocString( unicodeNativeString );
}

EDIT:

As a side-note, the other (not DLL-exported) GetFileInfo() function, returns a string&, but I'd suggest you to just return a string by value (i.e. just return string, not string&).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top