🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.g++.bug
Article #942

gcc 2.2.1 bug with default copy constructor generation...

#942
From: Lewis G. Pringle
Date: Fri, 11 Sep 1992 05:06
211 lines
4967 bytes
// Pardon the long bug report, but I saw no easy way to simplify the report, without
// looking at the ASM code generated.
//
// This is a bug report for g++ 2.2.1.
//
// Enclosed is some code which I believe demonstrates a bug with default generation of
// copy constructors. The code utilizes a simple string class that uses refernece
// counting on copys, and assignments etc. The reference counts get out of sync: which
// is the symtom of the bug. I believe this is because the compiler is not generating
// a proper copy constructor.
//
// If I manually define the copy constructor (Set WORK_AROUND_BUG to 1)
// then the code creates a list of length two, and both "Strings" are different. If
// I allow the compiler to define the copy construtor for me, then I think it
// fails to up the reference count so the storage for the first link is disposed of
// and is re-used by the next link when it calls new, and so we get aliasing.
//
// The program can be built and tested with
//	g++ -c WILMA.cc
//	g++ WILMA.o -o WILMA
// output of 
//	1
//	2
// indicates working correctly, and output of "oops" indicates a failure.
//

#define	WORK_AROUND_BUG	0

class	StringBuffer {
	public:
		StringBuffer (const char* cString):
			fLength (0),
			fStorage (0 )
		{
			fLength = strlen (cString);
			fStorage = ::new char [fLength];
			memcpy (fStorage, cString, fLength);
		}

		~StringBuffer ()
		{
			delete fStorage;
		}

		char*		Peek () const				{	return (fStorage);	}
		unsigned	GetLength () const		{return (fLength);	}

		unsigned	fLength;
		char*		fStorage;
		unsigned	fCount;
};

struct	String {
	String (const String& from);
	String (const char* cString);
	~String ();
 	String&	operator= (const String& newString);

	unsigned	GetLength () const				{	return (fPtr->GetLength ());	}
	const void*	Peek () const						{	return (fPtr->Peek ());	}

	StringBuffer*			fPtr;

};

String::String (const String& from):	
	fPtr (from.fPtr)
{
	if (fPtr) fPtr->fCount ++;
}

String::String (const char* cString):
	fPtr(0 )
{
	fPtr = new StringBuffer (cString);
	fPtr->fCount = 1;
}

String::~String ()	{
	if (fPtr) {
		fPtr->fCount--;
		if (fPtr->fCount == 0) {	
			delete fPtr;
		}
	}
}

String&	String::operator= (const String& newString)
{
	if (fPtr != newString.fPtr) {
		if (fPtr != 0) {
			fPtr->fCount--;	
			if (fPtr->fCount == 0) {
				delete fPtr;
			}
		}
		fPtr = newString.fPtr;
		if (fPtr != 0) {
			(fPtr->fCount)++;
		}
	}
	return (*this);
}

int	operator== (const String& lhs, const String& rhs)
{
  	if (lhs.fPtr == rhs.fPtr) {
		return (1);
	}
	if (lhs.GetLength () != rhs.GetLength ()) {
		return (0);
	}
	return (int (!memcmp (lhs.Peek (), rhs.Peek (), rhs.GetLength ())));
}

String	ltostring (unsigned l, int base = 10)
{
	unsigned long	ul		=	l;
	char			buf [1000];
	for (int i = 0; ul != 0; i++) {
		char	digit = char (ul % base);
		ul = ul / base;
		if (digit < 10) {
			buf [i] = '0' + digit;
		}
		else {
			buf [i] = 'A' + digit - 10;
		}
	}
	if (i == 0) {
		buf [i++] = '0';
	}
	buf [i] = '\0';

	char	reverse[sizeof (buf)];
	for (int ii = 0; ii < i; ii++) {
		reverse [ii] = buf [i-ii-1];
	}
	reverse [i] = '\0';
	return (reverse);
}



	struct	DictElt {
		String	fKey;
		unsigned	fElt;

		DictElt (String key, unsigned elt) :
			fKey (key),
			fElt (elt)
		{
		}

#if	WORK_AROUND_BUG
		DictElt (const DictElt& from) :
			fKey (from.fKey),
			fElt (from.fElt)
		{
		}
#endif
		~DictElt () {}

	};
	int	operator== (const DictElt& lhs, const DictElt& rhs)
	{
		return (int (lhs.fKey == rhs.fKey));
	}




struct	ListElt    {
	DictElt		fElement;
	ListElt*	fNext;
	ListElt    (DictElt element, 	ListElt   * next);
};
ListElt::ListElt (DictElt element, ListElt* next):
	fElement (element),	fNext (next)
{	
}	


int	Enter (ListElt*& table, DictElt elt)	 
{
	for (register 	ListElt   * curT = table; curT != 0 ; curT = curT->fNext) {
		if (curT->fElement == elt) {
			curT->fElement = elt;
			return (0);
		}
	}
	table =  new 	ListElt    (elt, table);
	return (1);
}


int	main (int, char*[])
{
	ListElt*	table = 0;
	for (int i = 1; i <= 2; i++) {
printf ("I=%d\n", i);
		DictElt de (ltostring (i), i);
		int r = Enter (table, de);
		if (!r) {
		  printf ("Ooops\n");		// We should never get here but we do with
		  				// the default compiler generated copy CTOR...
		  return (1);
		}
	}
	return (0);
}
Technical Details
Message-ID: <m0mT3Dc-000AWzC@sophists.com>
Path: arc1-ca.pugleaf.net!sparky!uunet!cis.ohio-state.edu!sophists.COM!lewis

Show Full Headers
Complete Article Headers
Newsgroups: gnu.g++.bug
Path: arc1-ca.pugleaf.net!sparky!uunet!cis.ohio-state.edu!sophists.COM!lewis
From: lewis@sophists.COM (Lewis G. Pringle)
Subject: gcc 2.2.1 bug with default copy constructor generation...
Message-ID: <m0mT3Dc-000AWzC@sophists.com>
Sender: gnulists@ai.mit.edu
Reply-To: lewis@sophists.com
Organization: GNUs Not Usenet
Distribution: gnu
Date: Fri, 11 Sep 1992 05:06:00 GMT
Approved: bug-g++@prep.ai.mit.edu
Lines: 212