Google Grupper støtter ikke lenger nye Usenet-innlegg eller -abonnementer. Historisk innhold er fortsatt synlig.

Is there a bug in MS ostrstream library?

Sett 10 ganger
Hopp til første uleste melding

Andrew Chalk

ulest,
30. apr. 2000, 03:00:0030.04.2000
til
In a VC++ 6.0 SP3 program I make 100+ calls to a construction semantically
identical to the following:

ostrstream os;
os << "MCTAPI: lineInitialize()=0x" << hex << lRc << endl << ends;
DoReportStatus(os.str());
os.freeze(false); // unfreeze to allow deallocation

where ostream is allocated as a local variable.

The "os <<" line causes several heap allocations and at the end of the
program there are no fewer than 5 of these heap blocks left unfreed. Here is
the output from the Crt... debug routines:

{549} normal block at 0x007F4AD0, 5 bytes long.
Data: <true > 74 72 75 65 00
{548} normal block at 0x007F4B10, 6 bytes long.
Data: <false > 66 61 6C 73 65 00
{547} normal block at 0x007F3120, 1 bytes long.
Data: < > 00
{542} normal block at 0x007F4BF0, 24 bytes long.
Data: <`wL 1 . > 60 77 4C 10 01 00 00 00 20 31 7F 00 2E 00 CD CD
{535} normal block at 0x007F3E50, 8 bytes long.
Data: < xL > 08 78 4C 10 01 00 00 00

This prompts three questions:

1) Am I deallocating ostrstream correctly? I chose:

os.freeze(false)

based on the "C++ Annotations" (majo...@icce.rug.nl). However, Eckel
"Effective C++" http://www.BruceEckel.com/ThinkingInCPP2e.html uses the
notation:

os.rdbuf()->freeze(0)

I am obviously going to try this method of freeing an ostrstream but before
I make 100+ changes in vain -- is anyone aware which method VC++ requires?

2) I single stepped through the line:

os << "MCTAPI: lineInitialize()=0x" << hex << lRc << endl << ends;

and found that the C++ heap allocator found that it had to allocate a new
block. Not the block for this memory allocation but apparently a new block
based on its internal allocation algorithm. Specifically, the C++ memory
allocator appears to allocate a larger block of heap than the first program
request wants (call the allocation a 'block'). It then divies this up on
subsequent program requests. When this block is used up, it allocates
another. In the program line above it was on heap allocation number 535 (see
the number on the left at the bottom of the debug output). It found that the
currently allocated block was full, and allocated another for me. However,
because this allocation was the 'new block allocation point' it did not
deallocate the block when ostrstream went out of scope.

I submit that this is a bug in VC++. Anyone else found this/replicated the
problem?

By way of confirmation, I commented out all of the above code and the
non-deallocated memory blocks reported at program exit just moved around.
This is consistent with my statement above that the compiler's failure to
deallocate heap occurs when it has to allocate a new 'block'

3) Is there an MS e-mail address for reporting compiler bugs that isn't a
black hole? At this point I'd even settle for GPS coordinates.

Many thanks for any help that any of you can give.

Regards.


Doug Harrison

ulest,
30. apr. 2000, 03:00:0030.04.2000
til
Andrew Chalk wrote:

It's not at all uncommon for memory managers not to ever return memory
allocated by malloc or new to the system. However, they certainly
should reuse memory they've already obtained that has been freed, and
VC does.

>I submit that this is a bug in VC++. Anyone else found this/replicated the
>problem?
>
>By way of confirmation, I commented out all of the above code and the
>non-deallocated memory blocks reported at program exit just moved around.
>This is consistent with my statement above that the compiler's failure to
>deallocate heap occurs when it has to allocate a new 'block'
>
>3) Is there an MS e-mail address for reporting compiler bugs that isn't a
>black hole? At this point I'd even settle for GPS coordinates.

I'm afraid you'll have to open a support incident, but you should have
received a couple of free ones with VC++. IME, MS doesn't decrement
your free incidents when they can't solve your problem.

However, I'm not sure you're seeing a genuine leak. First, MFC dumps
leaks when it terminates, and that can cause spurious leaks to be
reported for code which hasn't yet had a chance to free its memory,
such as the CRT. The CRT dumps leaks after it's destroyed static
duration data and run atexit() functions, i.e. at the right time, and
there's just no point in MFC dumping leaks. Unfortunately, I don't
know of any way to stop it. Second, not every memory allocation that
isn't freed represents a leak. For example, if some code allocates a
string that will be needed for the duration of the program, there's
little point in freeing it just before the program terminates; that
only has the potential to slow down program exit, sometimes
significantly, because the system might have to page that part of the
process back into memory to do it.

If you really want to get to the bottom of this, and the allocation
numbers are consistent, set an allocation number breakpoint at (say)
{549}, and look at the stack to see who's responsible. You should be
able to determine then if there's any code to free the memory and set
a breakpoint on it. That's what I did for the two spurious leaks I
always observe in my MFC apps, which are related to streams' use of
locales, IIRC.

--
Doug Harrison
d...@mvps.org
Visual C++ MVP

Rufus...@guntherintl.com

ulest,
1. mai 2000, 03:00:0001.05.2000
til

Doug Harrison wrote in message ...

<original problem snipped>

>If you really want to get to the bottom of this, and the allocation
>numbers are consistent, set an allocation number breakpoint at (say)
>{549}, and look at the stack to see who's responsible. You should be
>able to determine then if there's any code to free the memory and set
>a breakpoint on it.

That sounds like a useful technique. How do you set an allocation
number breakpoint?


Bull

ulest,
1. mai 2000, 03:00:0001.05.2000
til
> >If you really want to get to the bottom of this, and the allocation
> >numbers are consistent, set an allocation number breakpoint at (say)
> >{549}, and look at the stack to see who's responsible. You should be
> >able to determine then if there's any code to free the memory and set
> >a breakpoint on it.
>
> That sounds like a useful technique. How do you set an allocation
> number breakpoint?

_CrtSetBreakAlloc()

Bruce Dawson

ulest,
1. mai 2000, 03:00:0001.05.2000
til
ostrstream is a deprecated class. You should probably try using ostringstream
instead. Then you don't have to muck around with freeze().

If you suspect that the leak reports are spurious, try putting the same code in
a non-MFC program (console or Windows) to see if you still get the leak reports.
Spurious leak reports only happen in MFC apps. Note: you will have to turn
on leak detection or you will get no leak reports - test it by intentionally
leaking
one block of memory.

By the way, I think it is pathetic that the VC++ team went to all the effort to
create quite good leak detection code in the C run time library, only to have the

MFC team use it incorrectly and cause spurious leak reports. It is possible to
fix the problem in the MFC source, but then you have to rebuild MFC. What
a hassle.

Doug Harrison wrote:

--
.Bruce Dawson, Humongous Entertainment.
http://www.humongous.com/

Doug Harrison

ulest,
1. mai 2000, 03:00:0001.05.2000
til
Bruce Dawson wrote:

>By the way, I think it is pathetic that the VC++ team went to all the effort to
>create quite good leak detection code in the C run time library, only to have the
>
>MFC team use it incorrectly and cause spurious leak reports. It is possible to
>fix the problem in the MFC source, but then you have to rebuild MFC. What
>a hassle.

I have some DLLs that don't use MFC which I use in programs that do,
and they tend to load before MFC. Thus, when the MFC DLL exits, I get
spurious leaks for those DLLs. To work around this problem, I cause my
debug mode DLLs to link to the MFC DLL by forcing a reference to it in
a file "FixMFC.cpp":

#ifdef _DEBUG

#define _AFXDLL
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afx.h>

// Force linking to MFC.
static BOOL x = afxTraceEnabled;

#endif

This doesn't help the CRT, but at least it reduces the spurious leak
reports to a handful, typically two in my apps.

Bruce Dawson

ulest,
2. mai 2000, 03:00:0002.05.2000
til
Good solution.

I encourage everyone to report this as a bug to Microsoft so that we
won't have to do such hacks in the future. It's a trivial fix - it would be
nice if they make it. I've reported it, but I don't know whether they
listened.

By the way, here's the fixed code, in dumpinit.cpp:

_AFX_DEBUG_STATE::_AFX_DEBUG_STATE()
{
afxTraceEnabled = ::GetPrivateProfileInt(szDiagSection, szTraceEnabled,
TRUE, szIniFile);
afxTraceFlags = ::GetPrivateProfileInt(szDiagSection, szTraceFlags,
0, szIniFile);

#ifndef _AFX_NO_DEBUG_CRT
int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // New code added by Bruce
Dawson.
_CrtSetDbgFlag(nOldState | _CRTDBG_LEAK_CHECK_DF); // New code added by Bruce
Dawson.
ASSERT(pfnOldCrtDumpClient == NULL);
pfnOldCrtDumpClient = _CrtSetDumpClient(_AfxCrtDumpClient);

ASSERT(pfnOldCrtReportHook == NULL);
pfnOldCrtReportHook = _CrtSetReportHook(_AfxCrtReportHook);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW);
#endif // _AFX_NO_DEBUG_CRT
}

_AFX_DEBUG_STATE::~_AFX_DEBUG_STATE()
{
#ifndef _AFX_NO_DEBUG_CRT
//_CrtDumpMemoryLeaks(); Wrong, bad, stupid. Too early to report leaks.
//int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Wrong - don't turn off
//_CrtSetDbgFlag(nOldState & ~_CRTDBG_LEAK_CHECK_DF); // leak reporting.

_CrtSetReportHook(pfnOldCrtReportHook);
_CrtSetDumpClient(pfnOldCrtDumpClient);
#endif // _AFX_NO_DEBUG_CRT
}


Doug Harrison wrote:

> Bruce Dawson wrote:
>
> >By the way, I think it is pathetic that the VC++ team went to all the effort to
> >create quite good leak detection code in the C run time library, only to have the
> >
> >MFC team use it incorrectly and cause spurious leak reports. It is possible to
> >fix the problem in the MFC source, but then you have to rebuild MFC. What
> >a hassle.
>

> I have some DLLs that don't use MFC which I use in programs that do,
> and they tend to load before MFC. Thus, when the MFC DLL exits, I get
> spurious leaks for those DLLs. To work around this problem, I cause my
> debug mode DLLs to link to the MFC DLL by forcing a reference to it in
> a file "FixMFC.cpp":
>
> #ifdef _DEBUG
>
> #define _AFXDLL
> #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
> #include <afx.h>
>
> // Force linking to MFC.
> static BOOL x = afxTraceEnabled;
>
> #endif
>
> This doesn't help the CRT, but at least it reduces the spurious leak
> reports to a handful, typically two in my apps.
>

0 nye meldinger