Mail Archives: cygwin/2001/10/09/11:38:25
Hi,
Here is a short test program to reproduce a bug we've discovered with
gcc 2.95.3 targeted at Win32 (either cygwin or mingw).
The bug manifests itself as temporary objects which aren't destroyed.
This caused a large memory leak in our program. We narrowed it down
to a single form of statement
return _condition ? Example(2) + Example(3) : Example(4);
// ^^^^^^^^^^ this is the object that doesn't get destroyed!
It seems to need the return, the ? : and the creation of a temporary
object to trigger the bug. Unfortunately our code had rather a lot of
these statements in!
Compile the test program with:
gcc -Wall -pedantic cpp_bug.cc -o cpp_bug -lstdc++
It produces this when compiled native under linux
Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/specs
gcc version 2.95.3 20010315 (release)
Testing...
Creating object with value 42 at 0xbffffa10
Creating object with value 3 at 0xbffff9b0
Creating object with value 2 at 0xbffff9a0
Creating object with value 2 at 0xbffff960 from another
Creating object with value 5 at 0xbffffa00 from another
result = 5
However when compiled under native Windows cygwin it produces
Reading specs from /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/specs
gcc version 2.95.3-5 (cygwin special)
Testing...
Creating object with value 42 at 0x7afd1c
Creating object with value 3 at 0x7afc94
Creating object with value 2 at 0x7afc64
Creating object with value 2 at 0x7afbb4 from another
Creating object with value 5 at 0x7afcfc from another
result = 5
Oh no - 1 temporary object(s) did not have their destructors called!
object at 0x7afc64
Likewise when compiled under a cross compiled mingw
Reading specs from /usr/local/cross/mingw/lib/gcc-lib/i386-mingw32msvc/2.95.2/specs
gcc version 2.95.2 19991024 (release)
Testing...
Creating object with value 42 at 0259FDC8
Creating object with value 3 at 0259FD40
Creating object with value 2 at 0259FD10
Creating object with value 2 at 0259FC60 from another
Creating object with value 5 at 0259FDA8 from another
result = 5
Oh no - 1 temporary object(s) did not have their destructors called!
object at 0259FD10
Likewise or under a newer mingw
Reading specs from /usr/local/cross-tools/lib/gcc-lib/mingw32/2.95.3/specs
gcc version 2.95.3 20010315 (release)
Testing...
Creating object with value 42 at 0081FDC8
Creating object with value 3 at 0081FD40
Creating object with value 2 at 0081FD10
Creating object with value 2 at 0081FC60 from another
Creating object with value 5 at 0081FDA8 from another
result = 5
Oh no - 1 temporary object(s) did not have their destructors called!
object at 0081FD10
*/
//--------------------------------------------------------------------------------
/* test compiler for obscure C++ memory leak! */
#include <stdio.h>
#include <list>
class Example;
static list<Example *> track; // we keep track of all objects created and destroyed using this list
class Example
{
public:
Example(const int _value);
Example(const Example & _a);
~Example();
Example & operator+=(const Example & _a);
const int get_value() const { return value; }
Example test(const bool _condition);
private:
int value;
};
Example::Example(const int _value)
{
printf("Creating object with value %d at %p\n", _value, (void *)this);
value = _value;
track.push_back(this);
}
Example::Example(const Example & _a)
{
printf("Creating object with value %d at %p from another\n", _a.get_value(), (void *)this);
value = _a.get_value();
track.push_back(this);
}
Example::~Example()
{
for (list<Example *>::iterator i = track.begin(); i != track.end(); ++i)
{
if ((*i) == this)
{
track.erase(i);
return;
}
}
printf("Oops! Cannot find object of value %d at %p in list\n", value, (void *)this);
}
// We define + and += operators for our object the Stroustrup way...
Example & Example::operator+=(const Example & _a)
{
value += _a.get_value();
return *this;
}
Example operator+(const Example & _a, const Example & _b)
{
Example c(_a);
c += _b;
return c;
}
Example Example::test(const bool _condition)
{
return _condition ? Example(2) + Example(3) : Example(4);
// ^^^^^^^^^^ this is the object that doesn't get destroyed!
}
int main (int argc, char *argv[])
{
printf("Testing...\n");
// Do our little test - put in a scope of its own so all the temporary objects *should* get destroyed...
{
Example eg(42);
printf("result = %d\n", eg.test(true).get_value());
}
if (!track.empty())
{
printf("Oh no - %d temporary object(s) did not have their destructors called!\n", track.size());
for (list<Example *>::const_iterator i = track.begin(); i != track.end(); ++i)
{
printf(" object at %p\n", (void *)*i);
}
}
}
//--------------------------------------------------------------------------------
My colleague Nick Craig-Wood was kind enough to try out the above with
the different compilers described and thus confirm the bug.
Hope this is of some help to you!
Cheers
--
David Acton
Alphawave Ltd
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
- Raw text -