Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin AT sources DOT redhat DOT com X-Authentication-Warning: finisterre.office.alphawave.net: da set sender to da AT alphawave DOT net using -f Date: Tue, 9 Oct 2001 15:37:05 +0000 From: David Acton To: cygwin AT cygwin DOT com Subject: gcc bug - temporary objects not destroyed properly Message-ID: <20011009153705.A419@alphawave.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5i 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 #include class Example; static list 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::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::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/