{"id":481,"date":"2011-10-27T16:56:27","date_gmt":"2011-10-27T23:56:27","guid":{"rendered":"http:\/\/mattfife.net\/wordpress\/?p=481"},"modified":"2017-02-14T14:31:08","modified_gmt":"2017-02-14T21:31:08","slug":"why-stl-can-make-you-think-youre-leaking-memory-but-youre-not","status":"publish","type":"post","link":"https:\/\/mattfife.com\/?p=481","title":{"rendered":"Why _CrtDumpMemoryLeaks can make you think you\u2019re leaking memory &#8211; but you\u2019re not"},"content":{"rendered":"<p>I just spent an hour or two tracking down the last 16-byte memory leak in a project that I was working on. What it turned out to be was actually something\u00a0EXPLICITLY\u00a0cited in the Microsoft reference manual as having been fixed. \u00a0Yet it turned out not to be.<\/p>\n<p>I had finished instrumenting my program for CRT memory reporting. CRT memory leak reporting is normally very handy as it tells you exactly what lines of code are the source of the leak, how many bytes, and dumps the data that&#8217;s leaking. All it requires is that you instrument your headers as described\u00a0<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/x98tx3cf.aspx\" target=\"_blank\">here\u00a0<\/a>&lt;<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/x98tx3cf.aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/x98tx3cf.aspx<\/a>&gt;<\/p>\n<pre>\/\/ this goes before ANY other includes in ALL your headers\r\n#define _CRTDBG_MAP_ALLOC\r\n#include &lt;blah&gt;\r\n#include &lt;blah&gt;\r\n...\r\n<code> <\/code><code>main()\r\n{\r\n    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); \/\/ tells leak detector to dump report at any program exit\r\n    _CrtSetBreakAlloc(18); \/\/ set breakpoint on a specific allocation number\r\n}\r\n<\/code><\/pre>\n<p>With all this done you can run the program and then see the results of the report in the Visual studio output window when the program exits:<\/p>\n<pre>Detected memory leaks!\r\nDumping objects -&gt;\r\nC:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18}\r\nnormal block at 0x00780E80, 64 bytes long.\r\nData: &lt; &gt; CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD\r\nObject dump complete.\r\n<\/pre>\n<p><span class=\"Apple-style-span\">If you use the _CrtSetBreakAlloc() with the allocation number (<\/span><span class=\"Apple-style-span\" style=\"font-family: monospace; font-size: 13px;\">{18}<\/span><span class=\"Apple-style-span\">in this case), when the program starts up in debug mode the debugger will automatically stop on that allocation. You can then look at the call stack and get a great idea of whats leaking and why. Overall, it&#8217;s very handy and helped me track down all my leaks.<\/span><\/p>\n<p>Well, the problem\u00a0was that I fixed all the leaks but 2 in my particular program. \u00a0I reduced the code down until I was down to just main() that dumped the memory report and exited. \u00a0 The problem was that it STILL reported a\u00a0leak! I added a fake leak, and the very\u00a0first allocation (that was leaking) in the program had a higher allocation number than the allocations that were supposedly leaking. \u00a0This implied quite strongly that the leak is happening BEFORE I actually even get into the program. How is that possible?<\/p>\n<p>Well, there are a few things that get allocated for you before your program starts. Fixed-sized arrays, (int array[10];) string literals, and static variables are all objects are allocated on the stack (as opposed to the heap) are usually allocated at load time. When I looked at all the static allocations in my program, I saw this:<\/p>\n<pre>class Bar\r\n{\r\n    ...\r\nprivate:\r\n    static std::string m_name;\r\n    static std::string m_value;\r\n}\r\n<\/pre>\n<p>Do you see any problem? \u00a0I didn&#8217;t &#8211; at first. The problem is that std::string is a STL object that has a constructor. \u00a0Statics are usually allocated at load time. Which means their constructors are likely being called during load time BEFORE the main() is hit. We assume\u00a0that the corresponding destructors are called after main exits. Apparently, the CRT memory tracking starts right as the program starts but\u00a0is supposed to ignore any CRT allocations (ones made by the standard C libraries). \u00a0Apparently these static allocations by STL objects are captured. \u00a0Since we report leaks BEFORE we hit the program exit, we haven&#8217;t actually hit those &#8216;hidden&#8217;\u00a0destructors for those static strings yet. \u00a0Those allocations are still reported as active &#8211; and hence &#8216;leaked&#8217;. \u00a0I only caught this because I&#8217;d initialized those strings with string literals. \u00a0The leak dumped the memory and I recognized the strings. So a good way to test if this is happening to you is\u00a0set your object data\u00a0to something unique and make sure those unique values appear in\u00a0the leak report memory dump.<\/p>\n<p>Yet another clue is that the value of an uninitialized string consists of a number that appears to be a memory address (while the addresses change each run, other allocations in that run have roughly the same addresses), and a bunch of zeros. This likely corresponds to a pointer to the character buffer, and an int that indicates size. This is further confirmed by the fact the leaks are 8 bytes each in x86 build, and 16 bytes on a x64 build. This corresponds to the sizeof(int)+sizeof(void*) sizes on the respective builds.<\/p>\n<p><strong>Solution:<br \/>\n<\/strong>The solution is to ignore what is (likely) a false report, or change the static std::string objects to non-static or static std::string* pointers. Then make an appropriate initializer\/destructor that creates\/destroys\u00a0those string objects. This means the memory is allocated\/deallocated on the heap\u00a0in the scope of the program run. The other thing you do is file a bug with Microsoft and put a few comments on the documentation\u00a0website that indicates the statics are still leaking and they haven&#8217;t really fixed it yet. \ud83d\ude42<\/p>\n<p><strong>Links:<\/strong><br \/>\nMS article about CRT memory debug operations that says this bug had been fixed (but it has not as of VS2012)<\/p>\n<p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/x98tx3cf.aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/x98tx3cf.aspx<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I just spent an hour or two tracking down the last 16-byte memory leak in a project that I was working on. What it turned out to be was actually something\u00a0EXPLICITLY\u00a0cited in the Microsoft reference manual as having been fixed. \u00a0Yet it turned out not to be. I had finished instrumenting my program for CRT memory reporting. CRT memory leak reporting is normally very handy as it tells you exactly what lines of code are the source of the leak,&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/mattfife.com\/?p=481\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[],"class_list":["post-481","post","type-post","status-publish","format-standard","hentry","category-technicalprogramming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4WECr-7L","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/mattfife.com\/index.php?rest_route=\/wp\/v2\/posts\/481","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mattfife.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mattfife.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mattfife.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mattfife.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=481"}],"version-history":[{"count":5,"href":"https:\/\/mattfife.com\/index.php?rest_route=\/wp\/v2\/posts\/481\/revisions"}],"predecessor-version":[{"id":2823,"href":"https:\/\/mattfife.com\/index.php?rest_route=\/wp\/v2\/posts\/481\/revisions\/2823"}],"wp:attachment":[{"href":"https:\/\/mattfife.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=481"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mattfife.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=481"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mattfife.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}