[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gcc-bugs
Subject:    c++/2689: operator delete not called if constructor throws, 3.0 regression
From:       Philip Martin <pm () ntlworld ! com>
Date:       2001-04-29 20:02:07
[Download RAW message or body]


>Number:         2689
>Category:       c++
>Synopsis:       operator delete not called if constructor throws, 3.0 regression
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          wrong-code
>Submitter-Id:   net
>Arrival-Date:   Sun Apr 29 13:06:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Philip Martin
>Release:        3.0 20010428 (prerelease)
>Organization:
Corris Systems Ltd.
>Environment:
System: Linux debian2 2.2.19 #1 SMP Sun Apr 1 16:42:26 BST 2001 i686 unknown
Architecture: i686

	
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: /home/pm/gcc-cvs/gcc/configure --prefix=/usr/local/gcc-cvs --enable-languages=c,c++
>Description:
A member function operator delete with two arguments is not invoked if the
constructor throws. This is a regression from 2.95.2.

The following test case illustrates the problem:

$ g++ bug1.cc
$ a.out
Aborted
$ cat bug1.cc
#include <new>
extern "C" void abort();

bool new_flag = false;
bool delete_flag = false;

struct X {
   X()
   {
      throw 1;
   }
   void* operator new ( std::size_t n ) throw ( std::bad_alloc )
   {
      new_flag = true;
      return ::operator new( n );
   }
   void operator delete( void* p, std::size_t n ) throw()
   {
      delete_flag = true;
      ::operator delete( p );
   }
};

int
main()
{
   try
   {
      X* x = new X;  // gcc 3.0 fails to call operator delete when X::X throws
   }
   catch ( ... )
   {
   }
   if ( ! new_flag || ! delete_flag )
      ::abort();
}

>How-To-Repeat:
The preprocessed code:

# 1 "bug1.cc"
# 1 "/usr/local/gcc-cvs/include/g++-v3/new" 1 3
# 34 "/usr/local/gcc-cvs/include/g++-v3/new" 3
#pragma interface "new"
# 1 "/usr/local/gcc-cvs/include/g++-v3/cstddef" 1 3

# 1 "/usr/local/gcc-cvs/include/g++-v3/bits/std_cstddef.h" 1 3
# 40 "/usr/local/gcc-cvs/include/g++-v3/bits/std_cstddef.h" 3
# 1 "/usr/local/gcc-cvs/lib/gcc-lib/i686-pc-linux-gnu/3.0/include/stddef.h" 1 3
# 147 "/usr/local/gcc-cvs/lib/gcc-lib/i686-pc-linux-gnu/3.0/include/stddef.h" 3
typedef int ptrdiff_t;
# 199 "/usr/local/gcc-cvs/lib/gcc-lib/i686-pc-linux-gnu/3.0/include/stddef.h" 3
typedef unsigned int size_t;
# 41 "/usr/local/gcc-cvs/include/g++-v3/bits/std_cstddef.h" 2 3

namespace std
{
  using ::ptrdiff_t;
  using ::size_t;
}
# 3 "/usr/local/gcc-cvs/include/g++-v3/cstddef" 2 3
# 36 "/usr/local/gcc-cvs/include/g++-v3/new" 2 3
# 1 "/usr/local/gcc-cvs/include/g++-v3/exception" 1 3
# 34 "/usr/local/gcc-cvs/include/g++-v3/exception" 3
#pragma interface "exception"

extern "C++" {

namespace std
{
  class exception
  {
  public:
    exception() throw() { }
    virtual ~exception() throw() { }
    virtual const char* what() const throw();
  };

  class bad_exception : public exception
  {
  public:
    bad_exception() throw() { }
    virtual ~bad_exception() throw() { }
  };

  typedef void (*terminate_handler) ();
  typedef void (*unexpected_handler) ();

  terminate_handler set_terminate(terminate_handler) throw();
  void terminate() __attribute__ ((__noreturn__));

  unexpected_handler set_unexpected(unexpected_handler) throw();
  void unexpected() __attribute__ ((__noreturn__));

  bool uncaught_exception() throw();
}

}
# 37 "/usr/local/gcc-cvs/include/g++-v3/new" 2 3

extern "C++" {

namespace std
{
  class bad_alloc : public exception
  {
  public:
    virtual const char* what() const throw() { return "bad_alloc"; }
  };

  struct nothrow_t { };
  extern const nothrow_t nothrow;
  typedef void (*new_handler)();
  new_handler set_new_handler(new_handler);
}


void *operator new(std::size_t) throw (std::bad_alloc);
void *operator new[](std::size_t) throw (std::bad_alloc);
void operator delete(void *) throw();
void operator delete[](void *) throw();
void *operator new(std::size_t, const std::nothrow_t&) throw();
void *operator new[](std::size_t, const std::nothrow_t&) throw();
void operator delete(void *, const std::nothrow_t&) throw();
void operator delete[](void *, const std::nothrow_t&) throw();


inline void *operator new(std::size_t, void *place) throw() { return place; }
inline void *operator new[](std::size_t, void *place) throw() { return place; }
}
# 2 "bug1.cc" 2
extern "C" void abort();

bool new_flag = false;
bool delete_flag = false;

struct X {
   X()
   {
      throw 1;
   }
   void* operator new ( std::size_t n ) throw ( std::bad_alloc )
   {
      new_flag = true;
      return ::operator new( n );
   }
   void operator delete( void* p, std::size_t n ) throw()
   {
      delete_flag = true;
      ::operator delete( p );
   }
};

int
main()
{
   try
   {
      X* x = new X;
   }
   catch ( ... )
   {
   }
   if ( ! new_flag || ! delete_flag )
      ::abort();
}

>Fix:
Work around: the single argument operator delete works in the test case above.
>Release-Note:
>Audit-Trail:
>Unformatted:

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic