www.digitalmars.com         C & C++   DMDScript  

c++ - Incorrect stack unwinding when exception is thrown

reply stevetao <stevetao_member pathlink.com> writes:
DM 8.27 does not correctly unwind the stack when exception is thrown.  The
result of the following code should be.

Composite is created
Element no. 1 is created
Element no. 2 is created
Element no. 3 is created
Element no. 4 is created
Element no. 5 is created
Element no. 6 is created
Element no. 5 is destroyed
Element no. 4 is destroyed
Element no. 3 is destroyed
Element no. 2 is destroyed
Element no. 1 is destroyed
Exception is thrown

But DM 8.27 generate the following:

Composite is created
Element no. 1 is created
Element no. 2 is created
Element no. 3 is created
Element no. 4 is created
Element no. 5 is created
Element no. 6 is created
Exception is thrown

The code to demonstrate this problem is 

#include <iostream.h>

struct Exception {};

//--------------------------------------------------------------
class Element
{
public:
Element()
{
cout << "Element no. " << ++count << " is created\n";
if (count > 5)
{
--count;
throw Exception();
}    
}
virtual ~Element()
{
cout << "Element no. " << count-- << " is destroyed\n";
}
private:
static int count;
};

int Element::count = 0;

//--------------------------------------------------------------
class Composite
{
public:
Composite()
{
cout << "Composite is created\n";
pE = new Element[10];
}
virtual ~Composite()
{
delete [] pE;
cout << "Composite is destroyed\n";
}
private:
Element *pE;
};

//--------------------------------------------------------------
class Base
{
public:
Base()
{
pC = new Composite;
cout << "Constructing base\n";
}
virtual ~Base()
{
delete pC;
cout << "Destroying base\n";
}
private:
Composite *pC;
};

//--------------------------------------------------------------
class Derived : public Base
{
public:
Derived()
{
cout << "Constructing derived\n";
throw Exception();
}
virtual ~Derived()
{
cout << "Destroying derived\n";
}
};

//--------------------------------------------------------------
// main
//--------------------------------------------------------------
int main()
{
Base * p;

try {
p = new Derived;
}
catch( Exception e) {
cout << "Exception is thrown\n";
}

return 0;
}
Mar 26 2002
parent reply Jan Knepper <jan smartsoft.cc> writes:
I am not sure if this is stack unwinding or the fact that you throw an
exception during a new [] which does not revert the contructions by
destructing the constructed elements.

Jan



stevetao wrote:

 DM 8.27 does not correctly unwind the stack when exception is thrown.  The
 result of the following code should be.

 Composite is created
 Element no. 1 is created
 Element no. 2 is created
 Element no. 3 is created
 Element no. 4 is created
 Element no. 5 is created
 Element no. 6 is created
 Element no. 5 is destroyed
 Element no. 4 is destroyed
 Element no. 3 is destroyed
 Element no. 2 is destroyed
 Element no. 1 is destroyed
 Exception is thrown

 But DM 8.27 generate the following:

 Composite is created
 Element no. 1 is created
 Element no. 2 is created
 Element no. 3 is created
 Element no. 4 is created
 Element no. 5 is created
 Element no. 6 is created
 Exception is thrown

 The code to demonstrate this problem is

 #include <iostream.h>

 struct Exception {};

 //--------------------------------------------------------------
 class Element
 {
 public:
 Element()
 {
 cout << "Element no. " << ++count << " is created\n";
 if (count > 5)
 {
 --count;
 throw Exception();
 }
 }
 virtual ~Element()
 {
 cout << "Element no. " << count-- << " is destroyed\n";
 }
 private:
 static int count;
 };

 int Element::count = 0;

 //--------------------------------------------------------------
 class Composite
 {
 public:
 Composite()
 {
 cout << "Composite is created\n";
 pE = new Element[10];
 }
 virtual ~Composite()
 {
 delete [] pE;
 cout << "Composite is destroyed\n";
 }
 private:
 Element *pE;
 };

 //--------------------------------------------------------------
 class Base
 {
 public:
 Base()
 {
 pC = new Composite;
 cout << "Constructing base\n";
 }
 virtual ~Base()
 {
 delete pC;
 cout << "Destroying base\n";
 }
 private:
 Composite *pC;
 };

 //--------------------------------------------------------------
 class Derived : public Base
 {
 public:
 Derived()
 {
 cout << "Constructing derived\n";
 throw Exception();
 }
 virtual ~Derived()
 {
 cout << "Destroying derived\n";
 }
 };

 //--------------------------------------------------------------
 // main
 //--------------------------------------------------------------
 int main()
 {
 Base * p;

 try {
 p = new Derived;
 }
 catch( Exception e) {
 cout << "Exception is thrown\n";
 }

 return 0;
 }

Mar 26 2002
parent reply SteveTao <SteveTao_member pathlink.com> writes:
The code I provided was to demonstrate that if the exception is thrown during
the operator new [], the destructor of all created objects must be called.  

The code was working correctly with the following compilers:
1. Microsoft Visual C++ 6.0 - 7.0
2. Borland C++ 5.02 - 5.5.1
3. GNU GCC 2.95.0 - 3.04
4. Watcom C++ 11.0c
5. Metrowerks CodeWarrior 5 - 7

All these compilers properly called the destructor of all created objects if the
exception is thrown during the operator new [].  I originally guessed that the
problem was due to incorrect stack unwinding.

Steve

In article <3CA0B5E6.271CE29F smartsoft.cc>, Jan Knepper says...
I am not sure if this is stack unwinding or the fact that you throw an
exception during a new [] which does not revert the contructions by
destructing the constructed elements.

Jan

Mar 26 2002
next sibling parent Jan Knepper <jan smartsoft.cc> writes:
SteveTao wrote:

 The code I provided was to demonstrate that if the exception is thrown during
 the operator new [], the destructor of all created objects must be called.

 The code was working correctly with the following compilers:
 1. Microsoft Visual C++ 6.0 - 7.0
 2. Borland C++ 5.02 - 5.5.1
 3. GNU GCC 2.95.0 - 3.04
 4. Watcom C++ 11.0c
 5. Metrowerks CodeWarrior 5 - 7

 All these compilers properly called the destructor of all created objects if
the
 exception is thrown during the operator new [].  I originally guessed that the
 problem was due to incorrect stack unwinding.

The code shows that. I also noticed that it worked differently with other compilers. Jan
Mar 26 2002
prev sibling parent "Walter" <walter digitalmars.com> writes:
Thanks for posting the bug, I'll add it to the bug list. -Walter

"SteveTao" <SteveTao_member pathlink.com> wrote in message
news:a7qe95$13ne$1 digitaldaemon.com...
 The code I provided was to demonstrate that if the exception is thrown

 the operator new [], the destructor of all created objects must be called.

 The code was working correctly with the following compilers:
 1. Microsoft Visual C++ 6.0 - 7.0
 2. Borland C++ 5.02 - 5.5.1
 3. GNU GCC 2.95.0 - 3.04
 4. Watcom C++ 11.0c
 5. Metrowerks CodeWarrior 5 - 7

 All these compilers properly called the destructor of all created objects

 exception is thrown during the operator new [].  I originally guessed that

 problem was due to incorrect stack unwinding.

 Steve

 In article <3CA0B5E6.271CE29F smartsoft.cc>, Jan Knepper says...
I am not sure if this is stack unwinding or the fact that you throw an
exception during a new [] which does not revert the contructions by
destructing the constructed elements.

Jan


Mar 26 2002