[Bug c++/31289] New: gcc412 elides code in operator delete() override method
gcc-bugzilla at gcc dot gnu dot org
gcc-bugzilla@gcc.gnu.org
Wed Mar 21 00:31:00 GMT 2007
// BUG DEMO for gcc 4.1.2 (and 4.1.1) for 32-bit x86
//
// If operator delete() is over-ridden in a base class, then
// if the implementation of delete() stores into the storage used
// by the object, the store seems to be removed by the compiler
// (maybe because the compiler thinks stores to a deleted object
// are dead code? Or may be the casts of void * cause trouble
// with the C99 aliasing rules??)
//
// Only occurs with g++ -O3
// Occurs using native gcc on 32-bit x86.
// Does NOT occur with 64-bit x86.
// Does NOT occur with gcc 3.2.3
//
// The following program is a skeletal memory manager which maintains
// a separate free-list for each size object. Deleted objects are
// kept in a singly-linked list. operator delete() casts the void *
// pointer to be a pointer to an internal struct in order to store
// a "next" pointer in the first word of the storage block. The
// store through this cast pointer seems to be lost.
//
// TO DEMO THE PROBLEM:
// g++ -O3 thisfile.cpp && ./a.out
// (prints "ERROR" and then segfaults if the bug is there)
//
// -Jim Avera (jima@cadence.com)
// Please copy steele@cadence.com rking@cadence.com on all correspondence
//
#include <stdio.h>
#include <stdlib.h>
const size_t MaxSize = 100;
class MyHeap {
public:
MyHeap();
~MyHeap() {}
void * Malloc(const size_t bytes_needed);
void Free(void * ptr_to_free, size_t how_big_it_is);
void Dump(void);
struct Node {
Node *next;
};
private:
Node *Heads[MaxSize];
};
MyHeap::MyHeap() {
printf("MyHeap constructed\n");
for (int i=0; i < MaxSize; ++i) {
Heads[i] = 0;
}
}
void MyHeap::Dump(void)
{
printf("Dump of free-list data:\n");
int num_empties = 0;
for (int i=0; i < MaxSize; ++i) {
if (Heads[i] == 0) {
++num_empties;
} else {
printf(" Heads[%d] = %p\n", i, Heads[i]);
Node * next_node = Heads[i]->next;
if (next_node != 0) {
// For this test program, there should be exactly one item
printf(" ERROR: Expecting only one free item on list\n");
while (next_node != 0) {
printf(" next = %p\n", next_node);
next_node = next_node->next;
}
exit(1); // usually segfaults before getting here
}
}
}
printf("(%d lists are empty)\n", num_empties);
}
void * MyHeap::Malloc(const size_t bytes_needed)
{
if (bytes_needed < sizeof(Node) || bytes_needed > MaxSize) {
printf("MyHeap::Malloc - object too small or too large\n");
exit(1);
}
if (Heads[bytes_needed] == 0) {
// Pre-charge the free list with more storage
// (just one object for this test)
Node * newnode = static_cast<Node *>( malloc(bytes_needed) );
newnode->next = 0;
Heads[bytes_needed] = newnode;
}
// Detach the first from the list
Node * node = Heads[bytes_needed];
Heads[bytes_needed] = node->next;
return node;
}
void MyHeap::Free(void * ptr_to_free, size_t how_big_it_is)
{
// Put object on the free list
Node * node = static_cast<Node *>(ptr_to_free);
node->next = Heads[how_big_it_is];
Heads[how_big_it_is] = node;
}
// The memory-manager object
MyHeap my_pool;
class base {
public:
void * operator new(size_t bytes_needed)
{
void * raw_mem = my_pool.Malloc(bytes_needed);
return(raw_mem);
}
void operator delete(void * ptr_to_free, size_t how_big_it_is)
{
my_pool.Free(ptr_to_free, how_big_it_is);
}
};
class middle : public base {
public:
virtual ~middle() { }
};
class derived : public middle {
public:
derived() {
i = 11111111;
j = 22222222;
k = 33333333;
}
virtual ~derived() {
}
int i,j,k;
};
int main() {
setbuf(stdout,NULL); setbuf(stderr,NULL); // disable buffering
my_pool.Dump();
printf("new...\n");
derived *d = new derived;
printf("Got %p, sizeof=%u, raw dump follows:\n", d, (unsigned)sizeof(*d));
unsigned * up = reinterpret_cast<unsigned *>(d);
const size_t size_in_unsigneds = sizeof(*d)/sizeof(unsigned);
for (int ix=0; ix < size_in_unsigneds; ++ix) {
printf(" 0x%08x = %d\n", up[ix], up[ix]);
}
my_pool.Dump();
printf("delete...\n");
delete d;
my_pool.Dump();
printf("The bug was not detected\n");
return 0;
}
Environment:
System: Linux xba24 2.4.21-37.ELsmp #1 SMP Wed Sep 7 13:28:55 EDT 2005 i686
i686 i386 GNU/Linux
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with:
/grid/sfi/ct_src/gcc-v4.1.2/platforms/linux86/matrix_bootstrap_000/gcc-4.1.2/configure
--prefix=/grid/common/pkgs/gcc/v4.1.2 --mandir=/grid/common/pkgs/gcc/v4.1.2/man
--infodir=/grid/common/pkgs/gcc/v4.1.2/info --enable-shared
--enable-threads=posix --disable-checking --with-system-zlib
--enable-__cxa_atexit --with-gnu-as
--with-as=/grid/common/pkgs/binutils/v2.17/bin/as --with-gnu-ld
--with-ld=/grid/common/pkgs/binutils/v2.17/bin/ld --disable-libgcj
--with-local-prefix=/grid/common/pkgs/gcc/v4.1.2 --enable-clocale=gnu
--with-gmp=/grid/common/pkgs/gmp/v4.1.4 --enable-languages=c,c++,objc,fortran
How-To-Repeat:
Compile the supplied demo program with g++ -O3 and run it
--
Summary: gcc412 elides code in operator delete() override method
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: jima at cadence dot com
GCC build triplet: i686-pc-linux-gnu
GCC host triplet: i686-pc-linux-gnu
GCC target triplet: i686-pc-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31289
More information about the Gcc-bugs
mailing list