[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