Search code examples
mfcprotocol-buffers64-bitheap-corruption

Protobuf SerializeAsString causing heap debug assertion in x64


Sorry this will not be easily reproductible but maybe someone can help me along the way anyway!

I have a C++ MFC-based project (VS2019) that uses Google protobuf for communication with another C#-based application. When compiled under Win32, everything was working great. But we had to migrate to x64 and now Google protobuf functions SerializeToString and SerializeAsString causes a heap debug assertion when the generated string goes out of scope. The proto files are autogenereated from contract classes in the C# app, and I have the same problem with all of them.

Code snippet that generates the error:

auto test = API::myScope::MyTestDto();  //does not matter which protobuf class is being used
test.set_my_data(5);
{
   std::string newString = test.SerializeAsString();
   //Or use SerializeToString for same error:
   //std::string newString;
   //test.SerializeToString(&newString);
   ASSERT(newString.length() > 0);  //everything is fine here
}  // Causes assertion when newString goes out of scope.

The heap debug assertion that is being thrown:

  • File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
  • Line: 996
  • Expression: __acrt_first_block == header*

Here is the part of debug_heap that is throwing the assertion:

// Optionally reclaim memory:
if ((_crtDbgFlag & _CRTDBG_DELAY_FREE_MEM_DF) == 0)
{
    // Unlink this allocation from the global linked list:
    if (header->_block_header_next)
    {
        header->_block_header_next->_block_header_prev = header->_block_header_prev;
    }
    else
    {
        _ASSERTE(__acrt_last_block == header);
        __acrt_last_block = header->_block_header_prev;
    }

    if (header->_block_header_prev)
    {
        header->_block_header_prev->_block_header_next = header->_block_header_next;
    }
    else
    {
        _ASSERTE(__acrt_first_block == header);   //THIS LINE THROWING ASSERTION FAULT
        __acrt_first_block = header->_block_header_next;
    }

    memset(header, dead_land_fill, sizeof(_CrtMemBlockHeader) + header->_data_size + no_mans_land_size);
    _free_base(header);
}

Some more remarks:

The string seems to look okay... until it leaves scope and causes the crash.

I have tried recompiling the whole protobuf library from latest version, and I have tried regenerating all the autogenerated c++ protobuf code, but still the same error.

The app is multithreaded, but there is really nothing else going on at the same time that should be able to compete about the memory...

Has anyone expereinced this kind of error with the protobuf SerializeAsString function?

Or do you have any other debugging pointers that you could give me?

Since this is part of a huge project, I am actually afraid that there might be some other memory corruption error in the software that is causing this whole mess. But I cannot understand what could cause this sort of problem.


Solution

  • @Iinspectable was pointing me in the correct direction. The problem was that the libprotobuf was compiled as DLL, and the DLL versioning was causing heap errors. I had been compiling libprotobuf as DLL since that was used before in this project, but the protobuf readme file now says that compiling libprotobuf as static LIB is to be preferred, to avoid potential heap errors caused by DLL compilation.

    So I threw out the DLL and made a static LIB instead, problem solved!