delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2001/10/09/11:38:25

Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT sources DOT redhat DOT com>
List-Archive: <http://sources.redhat.com/ml/cygwin/>
List-Post: <mailto:cygwin AT sources DOT redhat DOT com>
List-Help: <mailto:cygwin-help AT sources DOT redhat DOT com>, <http://sources.redhat.com/ml/#faqs>
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 <da AT alphawave DOT net>
To: cygwin AT cygwin DOT com
Subject: gcc bug - temporary objects not destroyed properly
Message-ID: <20011009153705.A419@alphawave.net>
Mime-Version: 1.0
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 <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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019