Assert when using /MTd dynamic library

George Bromov 21 Reputation points
2021-01-21T18:09:30.273+00:00

I am trying to figure out why a very simple code leads to assert in free( ) when malloc( ) is called from different module.

I have two projects - executable and dynamic library.

The dynamic library has a single function:

void * __stdcall fn( ) { return malloc( 1024 ); } 

The executable is a console application with the following code:

int main() { free( fn( ) ); return 0; } 

When both projects are compiled with /MDd flag everything is fine. When they are compiled with /MTd flag, the free( ) call asserts:

Debug Assertion Failed!

Program: C:\Work\assert\Win32\Debug\assert.exe
File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 996

Expression: __acrt_first_block == header

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)

When in non-debug mode, using both /MT and /MD seems fine. Whether that's because there are no asserts( ) in release mode, or because the code is correct is unclear though.

Can anyone explain what is going on here. I can't imagine this code construct to be invalid, it should be possible for a dynamic library to allocate some memory that is going to be released from a different module. Is that just a /MTd issue? Is it safe to use /MDd for debug build to work around the assert, but to use /MT in release builds? I'd love to use /MT in release builds, shipping redistributables is quite annoying.

Thank you!

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,540 questions
0 comments No comments
{count} votes

Accepted answer
  1. Igor Tandetnik 1,106 Reputation points
    2021-01-21T19:12:03.65+00:00

    When you build with /MT[d], every module (EXE and DLL) contains its own copy of the C runtime, and in particular of the heap manager. One heap manager doesn't know what to do with a pointer allocated by another - from the first manager's point of view, it's just some random address.

    When you build with /MD[d], all modules share the same copy of C runtime DLL, and all use the same heap manager.

    This consideration applies to other resources (e.g. fopen in one module and fclose in another won't work with /MT)

    It's best not to spread resource management across modules: if the DLL provides a function for allocating memory, have it also provide a function that the EXE could call to deallocate it later. Otherwise, you have to ensure that all modules are built by the same compiler version, the same settings (e.g. Debug vs Release) and all use C runtime DLL (so /MD or /MDd).


0 additional answers

Sort by: Most helpful