Board index » cppbuilder » Re: SHOW STOPPING memory leak bug in C++ Builder

Re: SHOW STOPPING memory leak bug in C++ Builder


2005-09-08 07:23:59 PM
cppbuilder42
Zach Saw wrote:
Quote
Now we've got the unconstructive stuff out of the way, let me just
add that it only happens when you pass an AnsiString (as reference or
not) into the constructor. Haven't extensively tried other classes
though.
Well at least it gives us a test case for future versions of the
compiler.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Well, we'll need to carry on with our projects. How do I workaround this
problem?
"Andrue Cope [TeamB]" < XXXX@XXXXX.COM >wrote in message
Quote
Zach Saw wrote:

>Now we've got the unconstructive stuff out of the way, let me just
>add that it only happens when you pass an AnsiString (as reference or
>not) into the constructor. Haven't extensively tried other classes
>though.

Well at least it gives us a test case for future versions of the
compiler.

--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Zach Saw wrote:
Quote
I've lived with other bugs for years now, but this one is really one
that we can't get around. Is there a temporary work around of some
sort?
I can't immediately see one for the object.
Using a smart pointer for all data members solves the worst of the
problem in the example but may not be practical in a real project. It's
also not necessarily something you can trust given that the code is not
cleaning up correctly in the first place.
In any case it still leaves 4 bytes being leaked and with enough
objects being leaked this could be a problem. Even if the amount of
memory is small it could still easily lead to heap fragmentation.
Hopefully Alisdair has a better workaround since it sounds like he has
experience of this issue.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

{smallsort}

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Andrue Cope [TeamB] wrote:
Quote
Using a smart pointer for all data members solves the worst of the
problem in the example but may not be practical in a real project.
It's also not necessarily something you can trust given that the code
is not cleaning up correctly in the first place.
No. This doesn't work. I thought it did once but apparently not now.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Alisdair Meredith [TeamB] wrote:
Quote
This is a very puzzling bug and drove me nuts for years trying to pin
it down. I have done quite a lot of research on BCB destructor bugs
over the years, and there are a few reports in Quality Central that
might help.
OK, trying to find my reports again...
qc.borland.com/wc/qcmain.aspx
That is the nastiest one, that covers how the code gen changes
depending on whether or not an integer variable is declared before the
object that will fail to construct. Example is a little hard to read
online, but paste it into a code editor and it should help.
I can't find the report that mentions destructors not being called with
function inlining enabled, but at least that one has an implementable
workaround.
Again, I am hoping all the object lifetime bugs to be fixed in DeXter,
and hope the wait will not be too much longer. After all, year end is
less than 4 months away now (and after 3.5 years with BCB6, 4 months
actually begins to sound quite close ;?)
AlisdairM(TeamB)
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

"Andrue Cope [TeamB]" < XXXX@XXXXX.COM >wrote in message news: XXXX@XXXXX.COM ...
Quote
Zach Saw wrote:

>Windows can't possibly allocate 10Mb of memory??? You got me there!

You are indeed allocating 10MB chunks of memory (please, note the
capital 'B' for byte - 'b' means bit <s>) /but you are allocating
1000000 of them/. I'll paste the for() loop here again:

>for (int i=0; i<1000000; i++)
>{
>try
>{
>new LeakMe("test");
>}
>catch (const Exception &e)
>{
>}
>}

Do you see a call to 'delete' anywhere in there? I don't. Every pass of
that loop allocates 10MB to hold an instance of 'LeakMe'. Eventually
?? In c++ new is guaranteed to do nothing when a ctor doesn't
complete. The ctor throws here so nothing should be constructed
and there should be no leak. I wouldn't rely on task manager though.
What does codeguard say?
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Andrue Cope [TeamB] wrote:
Quote
>Using a smart pointer for all data members solves the worst of the
>problem in the example but may not be practical in a real project.
>It's also not necessarily something you can trust given that the
>code is not cleaning up correctly in the first place.

No. This doesn't work. I thought it did once but apparently not now.
Now it's just getting confusing. It seems to depend on exactly what is
in the class declaration. But this doesn't leak:
class LeakMe
{
boost::scoped_array<char>leaked;
public:
__fastcall LeakMe(const AnsiString &str)
{
leaked.reset( new char[ 1024 ] );
throw Exception("LEAKED!");
}
};
..nor this
class TTest
{
char test[ 10000 ];
};
class LeakMe
{
std::auto_ptr<TTest>leaked;
public:
__fastcall LeakMe(const AnsiString &str)
{
leaked.reset( new TTest() );
throw Exception("LEAKED!");
}
};
..Other than of course the object itself as already confirmed.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Duane Hebert wrote:
Quote
?? In c++ new is guaranteed to do nothing when a ctor doesn't
complete.
Yes, quite correct. My test project had Delphi exceptions turned off
and I missed the explicit throw.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Zach Saw wrote:
Quote
I don't think I have enabled inline functions (in fact, there isn't
even a destructor).
All I can suggest is that you check your project options - the majority
of these leaks (in practice) are due to that bug.
If that doesn't solve the problem, you need to start thinking how to
redesign your code around the problem. This is the only way to solve
the other category of bugs - double destruction, and destructors being
called for incomplete objects.
Generally I fall back on 2-phase construction. Implement a constructor
that is guaranteed not to throw, and then call the potentially-throwing
member function to complete contruction. This is best hidden behind a
factory function, so that you can hide 2-phase construction from the
rest of your system.
Yes, it is painful and should be un-necessary. In practice I seldom
need to go this far as disabling inlining solves most my problems, but
it is important to know the trick when needed.
Note you can make the second-phase function private, and your factory
function a friend or your class, or a static member if you prefer.
AlisdairM(TeamB)
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Duane Hebert wrote:
Quote
?? In c++ new is guaranteed to do nothing when a ctor doesn't
complete.
Not quite, but close <g>
If construction fails, new will hand back its resources - but can still
have effected internal changes in the memory manager. To all intents
and purposes it should not be observable, but as an example - memory
fragmentation is still a permitted behaviour, as is logging of the
calls etc.
AlisdairM(TeamB)
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

"Alisdair Meredith [TeamB]"
< XXXX@XXXXX.COM >wrote in message
Quote
>?? In c++ new is guaranteed to do nothing when a ctor doesn't
>complete.

Not quite, but close <g>
If construction fails, new will hand back its resources - but can still
have effected internal changes in the memory manager. To all intents
and purposes it should not be observable, but as an example - memory
fragmentation is still a permitted behaviour, as is logging of the
calls etc.
I was speaking wrt the object creation. I wasn't aware that c++ made
any guarantees about memory managers. My point is that this is
definitely a bug. We've had the same result here. FWIW, I don't
think the bug is with new(). It seems to me that it's a bug with the
ctor for ansistring that takes a const char. I think that if you create
the ansistring first and pass that to the ctor that this doesn't show
up. We've had similar problems when passing ansistrings between
threads.
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

"Zach Saw" < XXXX@XXXXX.COM >wrote in message
Quote
Well, we'll need to carry on with our projects. How do I workaround this
problem?
I can tell you what we've done to alleviate some of these problems:
Clear separation between GUI and non GUI stuff (treating AnsiString
as GUI stuff). This limits the cases where AnsiStrings get constructed
from const char*.
Try to control which AnsiString ctors are called. For example, create the
Ansistring explicitly to pass to the ctor.
Use STL for everything that's not directly GUI related with an interface
between the two to handle conversions.
Use boost::format and std::string to replace AnsiString
wherever possible.
Use std::vector<std::string>to replace TStringList wherever
possible.
This all adds complexity and reduces the RAD value of BCB
but we've found that we spend more time tracking down the
sort of bugs that you describe than the time we were saving.
Hopefully, Dexter will solve some of these problems. Even
so, separating the GUI stuff is basically a good design strategy
IMO.
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Alisdair Meredith [TeamB] wrote:
Quote
Yes, it is painful and should be un-necessary. In practice I seldom
need to go this far as disabling inlining solves most my problems, but
it is important to know the trick when needed.
Is disabling inlining something that can be done on a limited basis with
a pragma, or do you need to disable them for the entire project? I
would hate to think you'd be unable to use any inline functions in your
application just because one constructor is causing a problem.
--
Gillmer J. Derge [TeamB]
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

Gillmer J. Derge [TeamB] wrote:
Quote
Is disabling inlining something that can be done on a limited basis
with a pragma, or do you need to disable them for the entire project?
I would hate to think you'd be unable to use any inline functions in
your application just because one constructor is causing a problem.
Principle of least astonishment.
If you disable inlining everywhere, then you get consistent behaviour
and are rarely surprised.
If you selectively disable inlining when you detect a bug, your code
remains broken until you find the next bug and fix it. Working code
can end up breaking for the oddest reasons during maintenance.
The speed gains we saw in real-world examples from our code simply did
not justify the risk of enabling the feature - so we universally
disable it.
In specific benchmarks, such as using algorithms with vector< string>,
we have seen a factor of 30 or so when measuring speed. Howevever, our
GUI seems just as responsive, so we live with the trade-off.
It also makes project management much simpler - all projects are always
on full debug settings, even the final product.
Of course, we are generating in-house software. This might be a luxury
not afforded to others.
[we have been working with this policy for 3 or 4 years now, no real
user complaints]
AlisdairM(TeamB)
 

Re:Re: SHOW STOPPING memory leak bug in C++ Builder

I'm not sure our company has the resources to upgrade to Dexter when it does make it to the shelf. There are way too many things that we are using which also needs to be upgraded. It would be costing us too much money.
Whether the new version comes out or not, we've just purchased 4 new copies (3 of which is still wrapped in plastic). I'm sure we will feel violated if Borland does not solve the issue for this build, since to the consumers, this product is 1 week old.
I know TeamB is a voluntary group, so I personally am very much grateful for the work you guys are doing. I'm just wondering if you guys know any channels we can file our complaint and get an official response from Borland, since we are Borland's customer.
Thanks in advance.
"Alisdair Meredith [TeamB]" < XXXX@XXXXX.COM >wrote:
Quote
Alisdair Meredith [TeamB] wrote:

>This is a very puzzling bug and drove me nuts for years trying to pin
>it down. I have done quite a lot of research on BCB destructor bugs
>over the years, and there are a few reports in Quality Central that
>might help.

OK, trying to find my reports again...

qc.borland.com/wc/qcmain.aspx

That is the nastiest one, that covers how the code gen changes
depending on whether or not an integer variable is declared before the
object that will fail to construct. Example is a little hard to read
online, but paste it into a code editor and it should help.


I can't find the report that mentions destructors not being called with
function inlining enabled, but at least that one has an implementable
workaround.

Again, I am hoping all the object lifetime bugs to be fixed in DeXter,
and hope the wait will not be too much longer. After all, year end is
less than 4 months away now (and after 3.5 years with BCB6, 4 months
actually begins to sound quite close ;?)

AlisdairM(TeamB)