Article View: gnu.g++.bug
Article #942gcc 2.2.1 bug with default copy constructor generation...
From: Lewis G. Pringle
Date: Fri, 11 Sep 1992 05:06
Date: Fri, 11 Sep 1992 05:06
211 lines
4967 bytes
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!lewisShow 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