Archived

This topic is now archived and is closed to further replies.

ifstream and memory leaks

This topic is 5704 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, while working on a recent project I found that my app was leaking memory (reported by _CrtDumpMemoryLeaks() ) when tracking down the problem I isolated the function and the code that was causing the problem. I found it to be the following:
    
   ifstream in;
   in.open("readme.txt");
   in.close();
   
ok so your saying "he's got it wrong, and this isn't the code thats causing the problem. well just to check I worte the following program:
        
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <crtdbg.h>

using namespace std;

int main(int argc, char* argv[])
{
   ifstream in;
   in.open("readme.txt");
   in.close();

   _CrtDumpMemoryLeaks();

   return 0;
}
      
pretty technical stuff.. anyway here's the debug output when running the above program: Loaded 'ntdll.dll', no matching symbolic information found. Loaded 'C:\WINDOWS\SYSTEM32\KERNEL32.DLL', no matching symbolic information found. Detected memory leaks! Dumping objects -> {125} normal block at 0x00322848, 16 bytes long. Data: < > CC CD CD CD 00 00 00 00 00 00 00 00 00 00 00 00 {123} normal block at 0x00324120, 16 bytes long. Data: 6C 04 47 00 01 00 00 00 00 00 00 00 00 00 00 00 {122} normal block at 0x00323F28, 432 bytes long. Data: < ?2 ?2 ?2 ?2 > D4 3F 32 00 DF 3F 32 00 EA 3F 32 00 F6 3F 32 00 {121} normal block at 0x00323EE0, 12 bytes long. Data: < G (?2 > C4 04 47 00 01 00 00 00 28 3F 32 00 {120} normal block at 0x00323D88, 270 bytes long. Data: <: J a n : J a n > 3A 00 4A 00 61 00 6E 00 3A 00 4A 00 61 00 6E 00 {117} normal block at 0x00323CA0, 172 bytes long. Data: <: S u n : S u n > 3A 00 53 00 75 00 6E 00 3A 00 53 00 75 00 6E 00 {114} normal block at 0x00323C48, 16 bytes long. Data: < G <2 =2 > 14 06 47 00 01 00 00 00 A0 3C 32 00 88 3D 32 00 {113} normal block at 0x00323C00, 4 bytes long. Data: <- > 2D 00 00 00 {112} normal block at 0x00323BB8, 2 bytes long. Data: < > 00 00 {111} normal block at 0x00323B70, 2 bytes long. Data: < > 00 00 {110} normal block at 0x00323B28, 1 bytes long. Data: < > 00 {109} normal block at 0x00323AC0, 44 bytes long. Data: < G (;2 > E8 05 47 00 01 00 00 00 28 3B 32 00 00 00 00 00 {108} normal block at 0x00323A78, 4 bytes long. Data: <- > 2D 00 00 00 {107} normal block at 0x00323A30, 2 bytes long. Data: < > 00 00 {106} normal block at 0x003239E8, 2 bytes long. Data: < > 00 00 {105} normal block at 0x003239A0, 1 bytes long. Data: < > 00 {104} normal block at 0x00323938, 44 bytes long. Data: < G 92 > BC 05 47 00 01 00 00 00 A0 39 32 00 00 00 00 00 {103} normal block at 0x003238F0, 8 bytes long. Data: < G > 88 05 47 00 01 00 00 00 {102} normal block at 0x003238A8, 8 bytes long. Data: 78 05 47 00 01 00 00 00 {101} normal block at 0x00323860, 8 bytes long. Data: 79 00 65 00 73 00 00 00 {100} normal block at 0x00323818, 6 bytes long. Data: 6E 00 6F 00 00 00 {99} normal block at 0x003237C0, 16 bytes long. Data: <\ G 82 `82 > 5C 05 47 00 01 00 00 00 18 38 32 00 60 38 32 00 {98} normal block at 0x00323768, 16 bytes long. Data: 48 05 47 00 01 00 00 00 00 00 00 00 00 00 00 00 {97} normal block at 0x00323720, 10 bytes long. Data: 74 00 72 00 75 00 65 00 00 00 {96} normal block at 0x003236D8, 12 bytes long. Data: 66 00 61 00 6C 00 73 00 65 00 00 00 {95} normal block at 0x00323690, 1 bytes long. Data: < > 00 {94} normal block at 0x00323638, 24 bytes long. Data: <, G 62 . > 2C 05 47 00 01 00 00 00 90 36 32 00 2E 00 00 00 {93} normal block at 0x003235F0, 8 bytes long. Data: < G > 0C 05 47 00 01 00 00 00 {92} normal block at 0x003235A8, 8 bytes long. Data: < G > E0 04 47 00 01 00 00 00 {91} normal block at 0x00323360, 512 bytes long. Data: < > 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 {90} normal block at 0x00323308, 24 bytes long. Data: < G > 8C 04 47 00 01 00 00 00 00 00 00 00 00 00 00 00 {89} normal block at 0x00323110, 432 bytes long. Data: < 12 12 12 12 > BC 31 32 00 C7 31 32 00 D2 31 32 00 DE 31 32 00 {88} normal block at 0x003230C8, 12 bytes long. Data: 78 08 47 00 01 00 00 00 10 31 32 00 {87} normal block at 0x00322F18, 135 bytes long. Data: <:Jan:January:Feb> 3A 4A 61 6E 3A 4A 61 6E 75 61 72 79 3A 46 65 62 {84} normal block at 0x00322DD8, 86 bytes long. Data: <:Sun:Sunday:Mon:> 3A 53 75 6E 3A 53 75 6E 64 61 79 3A 4D 6F 6E 3A {81} normal block at 0x00322D80, 16 bytes long. Data: 58 08 47 00 01 00 00 00 D8 2D 32 00 18 2F 32 00 {80} normal block at 0x00322D38, 2 bytes long. Data: <- > 2D 00 {79} normal block at 0x00322CF0, 1 bytes long. Data: < > 00 {78} normal block at 0x00322CA8, 1 bytes long. Data: < > 00 {77} normal block at 0x00322C60, 1 bytes long. Data: < > 00 {76} normal block at 0x00322BF8, 44 bytes long. Data: <, G `,2 > 2C 08 47 00 01 00 00 00 60 2C 32 00 00 00 CD CD {75} normal block at 0x00322BB0, 2 bytes long. Data: <- > 2D 00 {74} normal block at 0x00322B68, 1 bytes long. Data: < > 00 {73} normal block at 0x00322B20, 1 bytes long. Data: < > 00 {72} normal block at 0x00322AD8, 1 bytes long. Data: < > 00 {71} normal block at 0x00322A70, 44 bytes long. Data: < G *2 > 00 08 47 00 01 00 00 00 D8 2A 32 00 00 00 CD CD {70} normal block at 0x00322A28, 8 bytes long. Data: < G > F0 07 47 00 01 00 00 00 {69} normal block at 0x003229E0, 8 bytes long. Data: < G > E0 07 47 00 01 00 00 00 {68} normal block at 0x00322998, 4 bytes long. Data: 79 65 73 00 {67} normal block at 0x00322950, 3 bytes long. Data: 6E 6F 00 {66} normal block at 0x003228F8, 16 bytes long. Data: < G P)2 )2 > CC 07 47 00 01 00 00 00 50 29 32 00 98 29 32 00 {65} normal block at 0x003228A0, 16 bytes long. Data: < G > B8 07 47 00 01 00 00 00 00 00 00 00 00 00 00 00 {63} normal block at 0x00322800, 5 bytes long. Data: <true > 74 72 75 65 00 {62} normal block at 0x003227B8, 6 bytes long. Data: 66 61 6C 73 65 00 {61} normal block at 0x00322770, 1 bytes long. Data: < > 00 {60} normal block at 0x00322718, 24 bytes long. Data: < G p'2 . > B8 03 47 00 01 00 00 00 70 27 32 00 2E 00 CD CD {59} normal block at 0x003226D0, 8 bytes long. Data: < G > 94 03 47 00 01 00 00 00 {58} normal block at 0x00322688, 8 bytes long. Data: 68 03 47 00 01 00 00 00 {57} normal block at 0x00320CE0, 128 bytes long. Data: < x 2 @ 2 &2 > 00 00 00 00 78 1D 32 00 40 0A 32 00 88 26 32 00 {56} normal block at 0x00320A98, 512 bytes long. Data: < > 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 {55} normal block at 0x00320A40, 24 bytes long. Data: < G > 14 03 47 00 01 00 00 00 00 00 00 00 00 00 00 00 {54} normal block at 0x003209D8, 33 bytes long. Data: < * > 00 2A 00 CD CD CD CD CD CD CD CD CD CD CD CD CD {50} normal block at 0x00321DD0, 40 bytes long. Data: < G 2 > 88 02 47 00 01 00 00 00 E0 0C 32 00 20 00 00 00 {43} normal block at 0x00321D78, 16 bytes long. Data: <4 G > 34 03 47 00 02 00 00 00 00 00 00 00 00 00 00 00 {41} normal block at 0x00320820, 33 bytes long. Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD {40} normal block at 0x003207B8, 40 bytes long. Data: < G > 88 02 47 00 18 00 00 00 00 00 00 00 00 00 00 00 Object dump complete. The thread 0x354 has exited with code 0 (0x0). The program 'C:\Under Development\CONSOLE1\Debug\CONSOLE1.exe' has exited with code 0 (0x0). By my reasoning I'm using the ifstream object correctly (as described in Schildt's C++ the complete ref. so my question is: is it me (what am I doing wrong) or is it the compiler/precompiled libraries. I also tried explicitly calling the destructor, which gave me a memory violation.. any help - this has me completely stumped, and I want to fix the problem.. thanks Toby Gobsmacked - by Toby Murray [edited by - tobymurray on May 6, 2002 10:28:59 AM]

Share this post


Link to post
Share on other sites
its certainly not a leak over time. and may not be a leak at all that function has a history of bad reports.

but to broaden the mystery this reports as a leak:
#include "stdafx.h"
#include <iostream>
#include <crtdbg.h>
using namespace std;
int main(int argc, char* argv[])
{

_CrtDumpMemoryLeaks();
return 0;
}

Now i asked myself what that means. noting that the line
#include <iostream> is the culprit. when its gone there is no leak. odd i thought cause its a header file and im not actually using anything. well in iostream the externs for all cin cout etc are declared. i bet that has alot to do with it.

but rest easy since it is most likely the standard stream objects causing it its also not going to be a leak over time. meaning it wont cause your app to do horrid things. and it could just be more screwy _CrtDumpMemoryLeaks interactions.

nothing to loose sleep over. i got no answers though.

Share this post


Link to post
Share on other sites
Thanks for your reply mate.
I agree with you that it probably won''t affect performance over time, but I''d like to be able to remove those error messages from the debug output so that if I actually have some "real" memory leak later on I won''t just assume that its not my fault (when in actual fact it will be)

does anyone know a good work around to stop those "erroneous" error messages appearing in the debug output?
(does the term "erroneous error messages" even make sense )


thanks
Toby

Gobsmacked - by Toby Murray

Share this post


Link to post
Share on other sites
It''s something that the CRTDebug system can''t get around; certain objects and resources are created/acquired before - and thus destroyed/released after - the CRTDebug system, so it reports them as leaks because they''re marked as belonging to your application.

There was a more complete description not too long ago (and I think NuMega BoundsChecker has the same problem).

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ ]
[ MS RTFM [MSDN] | SGI STL Docs | Boost ]
[ Google! | Asking Smart Questions | Jargon File ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
ya all that function does is set a flag in the debug system anyhow.

you can take over the work and check for leaks by comparing memory states. do a search on the whole name of the function in the library with VC++ and it gives good solid examples.

ive never used it but it looked easy enough to use. basically saving a state bookmark and handing the checking function the bookmark so it knows how far back to go on the heap. if you think the heap is clean back to that point then it should say its clean.

Share this post


Link to post
Share on other sites
The problem with the first test, as suggested, is that you''re reporting leaks before the ifstream object''s destructor is called. This would be a better test:

  
#include <fstream>
#include <iostream>
#include <crtdbg.h>
using namespace std;
int main(int argc, char* argv[])
{
{ // scope to allow auto object destruction

ifstream in;
in.open("readme.txt");
in.close();
}
_CrtDumpMemoryLeaks();
return 0;
}

But you''re still left with some leaks:

{68} normal block at 0x00301840, 512 bytes long.
Data: < > 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
{55} normal block at 0x00300030, 16 bytes long.
Data: <@wL > 40 77 4C 10 01 00 00 00 00 00 00 00 00 00 00 00
{47} normal block at 0x00301D90, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
{46} normal block at 0x00301DE0, 40 bytes long.
Data: < |L > 14 7C 4C 10 16 00 00 00 00 00 00 00 00 00 00 00

The problem is that MS''s libraries dynamically allocate memory to static variables, which are then released in an atexit handler. There''s no possible way you can guarantee that leak-checking software will report its findings after all the atexit handlers have executed; IOW, there''s always a chance of false leaks. We ran into this problem with our own libraries, where we knew statics were being released (we set breakpoints, the code was called!) but BoundsChecker was reporting the leaks. Finally we realized that the leak report was coming _before_ our breakpoints on the release functions were hit. NuMega says as much in their readme, and lists the bug in their FAQ:
http://frontline.compuware.com/nashua/kb/doc/155.asp

Something you can do is look at the memory allocations themselves. That first number in curly braces is the memory allocation number that has leaked. Normally, you''d be able to use _CrtSetBreakAlloc, and you can for some of the later ones. Example: Insert _CrtSetBreakAlloc (68) as your first line in main (this is the big 512 byte one). The debugger will break on that allocation, allowing you to step into where the allocation takes place. You''ll notice (if you''re using MSVC 6.0) that the function _Getctype in _TOLOWER.C is the culprit, and it looks like it just mallocs some memory then leaks. But if you follow this call further up the chain, you''ll see that this is part of the ctype<char>::Init function:

  
void _Init(const _Locinfo& _Lobj)
{_Lockit Lk;
_Ctype = _Lobj._Getctype(); // malloc was here..

if (_Cltab == 0)
{_Cltab = _Ctype._Table;
atexit(_Term); // wot''s this?!

_Ctype._Delfl = false; }}

Step into that call, and you''ll see that the atexit(_Term) path is taken right after your allocation (wot''s this?!), and that the _Term function is:

  
static void __cdecl _Term(void)
{free((void *)_Cltab); }

Set a breakpoint on that line and you''ll see that the 512 bytes of memory ARE indeed freed--AFTER your call to _CrtDumpMemoryLeaks.

Likewise, alloc 55 happens in the facet code of XLOCALE, and it''s freed by the _TidyFac::_Tidy () function, registered as an atexit handler through the _Save function that allocates the pointer in the first place.

Unfortunately, the other leaks are more difficult to track down because those allocations have happened before you''ve even gotten to the first line of main (in my program, the current request counter "_lRequestCurr" reads 52 when I set the debug point). The only way to do this is to set a breakpoint in malloc, and then set a debug break flag when _lRequestCurr reaches your number (kinda advanced breakpointing stuff, since you have to set this breakpoing inside the DBGHEAP.C file context in the debugger).

Doing this, I find that the memory allocations are in LOCALE0.CPP, locale::Init () (which is released by a atexit(_Tidy()) call)--this is the 40 byte allocation. And finally, the 33 bytes come (eventually) from the same file, locale::_Locimp ctor, which creates an empty string which is eventually released by a call to basic_string::_Tidy ().

This took a little longer than I planned, but hopefully that answers your questions. Hopefully I''ve given the listeners here the understanding of why some leaks are reported falsely and the ability to track down their own leaks if need be. The moral of the story is to learn which leaks to ignore--any reasonably complex project is bound to have false leaks.

Share this post


Link to post
Share on other sites
Or in my case, true-false leaks: STLPort likes to leave a couple of hundred kilobytes of memory around during my program''s execution, because it''s inefficient to delete it. You know, just in case I will need it later. *sigh*

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files ]

Share this post


Link to post
Share on other sites
Try putting this as your first line of main(), and remove the other _CrtDumpMemLeaks():


    
// Must be first first line in main()

#ifdef _DEBUG
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

It won't catch any leaks for memory allocated before entering main(), but it doesn't report fake leaks with your sample code.

[edited by - Z01 on May 6, 2002 9:23:59 PM]

Share this post


Link to post
Share on other sites