LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 27 - Constructors and destructors are not interacting with exceptions quite right
Summary: Constructors and destructors are not interacting with exceptions quite right
Status: RESOLVED FIXED
Alias: None
Product: tools
Classification: Unclassified
Component: llvm-g++ (show other bugs)
Version: trunk
Hardware: PC Linux
: P normal
Assignee: Chris Lattner
URL:
Keywords: miscompilation
Depends on:
Blocks:
 
Reported: 2003-10-09 15:17 PDT by Chris Lattner
Modified: 2010-02-22 12:51 PST (History)
1 user (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Lattner 2003-10-09 15:17:15 PDT
The following testcase is being miscompiled.  This was extracted from the GCC EH
newbies guide.

// Testcase for proper handling of
// c++ type, constructors and destructors.

#include <stdio.h>

int c, d;

struct A
{
  int i;
  A () { i = ++c; printf ("A() %d\n", i); }
  A (const A&) { i = ++c; printf ("A(const A&) %d\n", i); }
  ~A() { printf ("~A() %d\n", i); ++d; }
};

void
f()
{
  printf ("Throwing 1...\n");
  throw A();
}


int main() {
  try
    {
      f();
    }
  catch (A)
    {
      printf ("Caught.\n");
    }
  printf ("c == %d, d == %d\n", c, d);
  return c != d;
}


You should get the following output:

Throwing 1...
A() 1
A(const A&) 2
~A() 1
A(const A&) 3
Caught.
~A() 3
~A() 2
c == 3, d == 3
Comment 1 Chris Lattner 2003-10-10 11:24:52 PDT
As it turns out, the first bug is that the C++ front-end is producing a
memberwise copy of the thrown object into the exception object: it is not
invoking the copy constructor in "f()".
Comment 2 Chris Lattner 2003-10-10 12:45:17 PDT
Some progress on this bug:

 * TARGET_EXPR's were not expanding into their destination if 
   available correctly, causing extra copying to occur.  This 
   should not be a correctness problem, but is wasteful, and 
   inefficient.  This is now fixed.
 * The C++ front-end is eliding the first construct, copy ctor,
   and dtor calls, instead, just evaluating the ctor directly 
   into the exception object.  This is fine, and disablable with
   -fno-elide-constructors.

FWIW, we are getting this output with -felide-constructors:
Throwing 1...
A() 1
~A() 1
A(const A&) 2
~A() 2
Caught.
~A() 2
~A() 134523024
c == 2, d == 4

and this with -felid-constructors:
Throwing 1...
A() 1
A(const A&) 2
~A() 2
~A() 1
A(const A&) 3
~A() 3
Caught.
~A() 3
~A() 134523088
c == 3, d == 5


There is still a bug though, because c != d.
Comment 3 Chris Lattner 2003-10-10 17:44:22 PDT
It turns out that the major part of this problem was not code-generating
TARGET_EXPRs correctly.  It seems that the cleanups should only be run if they
are "orphaned", and we were running them always.  This now brings the testcase to:

Throwing 1...
A() 1
A(const A&) 2
Caught.
~A() 2
~A() 134522992
c == 2, d == 2

Which is almost exactly right (just s/134522992/1/)
Comment 4 Chris Lattner 2003-10-10 17:57:43 PDT
Ok, the final piece of this puzzle was in the C++ EH runtime library, not
passing the correct object pointer into the object destructor:
http://mail.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20031006/007943.html

This bug is now fixed.