This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

gcc bug - temporary objects not destroyed properly


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/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]