header image
 

CRT in DLLs and memory allocation

This is how a debug build behaves, compiled with VS2013. Release build is different and the differences are a bit baffling. I’ll write about that later.

I’ve spent a lot of time hunting an elusive memory corruption bug. At least it looked like memory corruption: release build just crashed on access violation, debug build was throwing a CRT assert on free().

CRT debug heap assertion

CRT debug heap assertion

Evidently something was wrong with the heap when free() was called — debug builds perform heap checking after a certain number of heap operations. You can force heap checking at every (de)allocation with _CrtSetDbgFlag(), it’s a good idea in cases like this when it wasn’t immediately obvious why the free() would cause problems. The memory was good, no double-freeing was occurring. Yet commenting that free() out seemed to remove all problems (memory leaks notwithstanding).

I’ve been scratching my head for a bit, tried the Application Verifier, nothing seemed to bring me closer to diagnosing the core issue. Finally I analyzed where this freed memory was coming from. It was allocated in a call imported from a utility DLL. Gears started to move faster in my head when I checked the DLL’s project settings, specifically how the C runtime was linked. It was linked statically.

Why was that causing problems? Well, when the CRT is statically linked to a DLL, that DLL creates its own CRT heap for your malloc()s and free()s. That means if you malloc() something in a DLL with static CRT you can’t free() it from the main program because the free() will operate on a different CRT heap. You can see the virtual memory breakdown of a process with VMMap, an excellent Sysinternals utility.

Heaps with static CRT DLL

Heaps with static CRT DLL

Heaps with dynamic CRT DLL

Heaps with dynamic CRT DLL

We can see the additional heaps when the DLL contains statically linked CRT.

What’s the moral of the story?

  • Never link the CRT statically unless you really know what you’re doing. It may be tempting to avoid the need of CRT run-time DLLs but it’s almost always not worth it. Why duplicate the CRT code in your executables? Just ship the CRT redistributables with your installer.
  • If you really need static CRT in your DLL, free all DLL-allocated memory in the DLL, not outside of it.

~ by omeg on June 16, 2015.

C/C++, code, troubleshooting

Leave a Reply