2 Replies Latest reply on Jul 6, 2010 10:25 AM by santosh.zanjurne

    Bug: Spurious destructor called in short-circuit expression

    cdmuhlb
      Compiler tries to destruct an object that was never created

      I think we have found a bug in Open64's C++ compiler.  The bug appears to be triggered when a constructor is invoked in nested short-circuit expressions.  Upon execution, when the short-circuit skips the constructor, the object's destructor is called on a random location in memory.

      Attached is some code that reproduces the problem.  The "Token" object is just along for the ride, but is explicitly copied on the RHS of a short-circuit expression.  The expected output is something like this, where the number in parentheses counts the number of tokens in existence:

      New Token @ 0x7fffad9ed45f (1)
      Cpy Token @ 0x7fffad9ed35f (2)
      Del Token @ 0x7fffad9ed35f (1)
      Del Token @ 0x7fffad9ed45f (0)

      However, on Open64, the output is this:

      New Token @ 0x7fff1c290670 (1)
      Cpy Token @ 0x7fff1c2905d0 (2)
      Del Token @ 0x7fff1c2905d0 (1)
      Del Token @ 0x7fff1c290620 (0)
      Del Token @ 0x7fff1c290670 (-1)

      The destructor for Token is spuriously called on random memory (in this case, 0x7fff1c290620).  This bug is present in both Open64 4.2.2 and Open64 4.2.3 and also in the Pathscale compilers.  (Correct output is produced by GCC, Intel, Sun Studio, and PGI.)

      With non-trivial destructors, this bug has serious consequences (segfaults, silent corruption, etc.), and since it is triggered in portions of our research code, we have had to switch to slower compilers.  It would be great if this bug could be fixed in a future release of Open64.  If there is a more appropriate place than the forums to report such problems, please let me know.  Thank you for any assistance you can provide!

      #include <iostream> using namespace std; class Token { public: Token() { ++count; cout << "New Token @ " << this << " (" << count << ")" << endl; } ~Token() { --count; cout << "Del Token @ " << this << " (" << count << ")" << endl; } Token(const Token & x) { ++count; cout << "Cpy Token @ " << this << " (" << count << ")" << endl; } private: static int count; }; int Token::count = 0; class BoolExpr { public: virtual bool eval(const Token & x) = 0; }; class FalseVal : public BoolExpr { public: bool eval(const Token & x) { return false; } }; class TrueVal : public BoolExpr { public: bool eval(const Token & x) { return true; } }; class AndOp : public BoolExpr { public: AndOp(BoolExpr * a, BoolExpr * b) : expr1(a), expr2(b) {} bool eval(const Token & x) { return expr1->eval(x) && expr2->eval(Token(x)); } private: BoolExpr * expr1; BoolExpr * expr2; }; int main(int argc, char * argv[]) { TrueVal t; FalseVal f; AndOp atf(&t, &f); AndOp aatft(&atf, &t); aatft.eval(Token()); return 0; }