Search code examples
c++c++-cliclrmarshallingstdstring

Runtime exception in std::string delete operator when converting System::String to std::string


I'm using C++ cli solution with both C# and C++ code.

When I try to convert System::String to std::string I'm getting the following runtime exception on every run:

ucrtbased.dll!00007ffd9902b9b0()    Unknown
ucrtbased.dll!00007ffd9902eac5()    Unknown
MyApp.dll!operator delete(void * block) Line 21 C++
[Managed to Native Transition]  
MyApp.dll!std::_Deallocate(void* _Ptr, unsigned __int64 _Count, unsigned __int64 _Sz) Line 133  C++
MyApp.dll!std::allocator<char>::deallocate(char* _Ptr, unsigned __int64 _Count) Line 721    C++
MyApp.dll!std::_Wrap_alloc<std::allocator<char> >::deallocate(char* _Ptr, unsigned __int64 _Count) Line 988 C++
MyApp.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(bool _Built, unsigned __int64 _Newsize) Line 2260 C++
MyApp.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::=(std::basic_string<char,std::char_traits<char>,std::allocator<char> >& _Right) Line 934    C++
MyApp.dll!MyApp::DoStuff(System::String^ input) Line 59 C++

Or when I run without Debugger:

error

My code, I tried two options, both resulted with same crash:

Option 1

void MyApp::DoStuff(System::String^ input) {
    msclr::interop::marshal_context context;
    std::string converted = context.marshal_as<const char*>(LicenseOEM);
}

Option 2

std::string SystemToStd(System::String^ sys) {
    int len = sys->Length;
    char* buff = (char*)malloc((len + 1) * sizeof(char));
    for (int i = 0; i < sys->Length; i++) {
        buff[i] = sys[i];
    }
    buff[len] = '\0';
    std::string str = std::string(buff, len);
    free(buff);
    return str;
}

void MyApp::DoStuff(System::String^ input) {
    std::string converted = SystemToStd(LicenseOEM);
}

Solution

  • maybe this is a C++ theme on it's own.

    Did you ensure to bind the right/fitting/same runtime dlls for your configuration.

    The debug dlls from microsoft (the others i don't know) try to find out if somebody corrupts the memory. They do so by providing a different implementation of new/delete. Basically they enlarge the allocated memory, to have unused memory before and after your allocated memory. Then they fill it with a pattern and information and give you the pointer to your object. When delete/freeing the object, they obtain the right value for your memory area and control the information and if somebody has overwritten the patterns before and after your object.

    So you try to bind a dll which was compiled with release as configuration. But now you try to find out something, use debug, and forget now your runtime dlls do not match then your code is creating it with debug information, but you provide this object to a native/cpp function, which was compiled with release and the try to free the object, which is not working. Or vice versa release std:string is freed with debug delete.

    Actually i googled your failure message and some hints in the same direction, so you might recheck Debug Assertion Failed! Expression: __acrt_first_block == header