mt_allocator: static DE-initialization order fiasco?
Carlo Wood
carlo@alinoe.com
Tue Oct 12 00:07:00 GMT 2004
On Mon, Oct 11, 2004 at 02:14:07AM +0200, Paolo Carlini wrote:
> |Therefore, if you are getting into serious troubles using __mt_alloc
> directly, the same will happen if you just use std::allocator. Consider
> that mt_allocator is now the default in the build, therefore, if you
> just select the right policy via a typedef in include/ext/mt_allocator.h
> and rebuild the library you can very easily double check what I said.
>
> Please, if you have a small testcase contribute it.
Ugh that wasn't easy :/.
I used "testsuite/ext/mt_allocator/deallocate_global-4.cc"
as a starting point. However, I was forced to use more than
one shared library in order to enforce the deinitialization
fiasco to actually happen.
With the attached files, which I attached one by one so that
you can already see them without first saving the tar ball
first, you should be able to reproduce the following.
I also attached everything together as test.tar.bz2 for your
convenience.
$ make
g++-cvs-4.0 -I. -g -shared -o libfoo.so foo.cc memblk.cc
g++-cvs-4.0 -I. -g -shared -o libglobal1.so global1.cc
g++-cvs-4.0 -I. -g -shared -o libglobal2.so global2.cc
g++-cvs-4.0 -I. -g -L. -Wl,-rpath,`pwd` -lglobal1 -lfoo -lglobal2
$ ./a.out
Calling: operator new(258) = 0x804a008
Calling: operator new(100) = 0x804a110
Calling: operator new(4) = 0x804a178
Calling: operator new(4) = 0x804a188
Calling: operator new(4) = 0x804a198
Calling: operator new(4) = 0x804a1a8
Calling: operator new(4) = 0x804a1b8
Calling: operator new(4080) = 0x804a1c8
Calling: operator new(8) = 0x804b1c0
Calling: operator new(258) = 0x804b1d0
Calling: operator new(40) = 0x804b2d8
Calling: operator new(4) = 0x804b308
Calling: operator new(4) = 0x804b318
Calling: operator new(4) = 0x804b328
Calling: operator new(4) = 0x804b338
Calling: operator new(4) = 0x804b348
Calling: operator new(4080) = 0x804b358
Calling: operator new(8) = 0x804c350
Starting destruction.
Destructing object "global1.cc" which is using memory at 0x804b3bc.
This memory belongs to a memory block starting at 0x804b358 with size 4080.
Calling: delete 0x804b308
Calling: delete 0x804b318
Calling: delete 0x804b358 <=== range: [0x804b358 - 0x804c348)
Calling: delete 0x804c350
Calling: delete 0x804b328
Calling: delete 0x804b338
Calling: delete 0x804b348
Calling: delete 0x804b2d8
Calling: delete 0x804b1d0
Destructing object "foo.cc" which is using memory at 0x804b394.
Calling: operator new(4080) = 0x804b1d0
Calling: operator new(8) = 0x804c1c8
terminate called after throwing an instance of 'std::runtime_error'
what(): Allocation is already freed
Aborted
As you can see, the object "foo.cc" is using memory at 0x804b394
that falls in the range [0x804b358 - 0x804c348) of a memory block
that already freed.
--
Carlo Wood <carlo@alinoe.com>
-------------- next part --------------
CXX=g++-cvs-4.0
HEADERS=Global.h string_t.h memblk.h
a.out: libfoo.so libglobal1.so libglobal2.so
$(CXX) -I. -g -L. -Wl,-rpath,`pwd` -lglobal1 -lfoo -lglobal2
libfoo.so: foo.cc memblk.cc $(HEADERS)
$(CXX) -I. -g -shared -o libfoo.so foo.cc memblk.cc
libglobal1.so: global1.cc $(HEADERS)
$(CXX) -I. -g -shared -o libglobal1.so global1.cc
libglobal2.so: global2.cc $(HEADERS)
$(CXX) -I. -g -shared -o libglobal2.so global2.cc
clean:
rm -f *.o *.so a.out
-------------- next part --------------
#ifndef STRING_T_H
#define STRING_T_H
#include <string>
#include <ext/mt_allocator.h>
// This is copied from testsuite/ext/mt_allocator/deallocate_global-4.cc
typedef char char_t;
typedef std::char_traits<char_t> traits_t;
typedef __gnu_cxx::__per_type_pool_policy<char_t, false> pool_t;
typedef __gnu_cxx::__mt_alloc<char_t, pool_t> allocator_t;
typedef std::basic_string<char_t, traits_t, allocator_t> string_t;
#endif // STRING_T_H
-------------- next part --------------
#ifndef MEMBLK_H
#define MEMBLK_H
struct memblk {
void* ptr;
size_t size;
};
memblk* find_allocation(void const*);
#endif // MEMBLK_H
-------------- next part --------------
#ifndef GLOBAL_H
#define GLOBAL_H
#include <string>
#include "string_t.h"
struct Global {
std::string _M_name;
string_t _M_use_same_pool;
Global(std::string const& name) : _M_name(name), _M_use_same_pool("XXXX") { }
~Global();
};
#endif // GLOBAL_H
-------------- next part --------------
#include <stdexcept>
#include <cassert>
#include "string_t.h"
#include "memblk.h"
static memblk memblocks[100];
memblk* find_allocation(void const* ptr)
{
memblk* head = memblocks;
while (head->ptr > ptr || ((char*)head->ptr + head->size) <= (char*)ptr)
{
++head;
if (head == &memblocks[100])
throw std::runtime_error("Allocation is already freed");
}
return head;
}
void* operator new(size_t size) throw(std::bad_alloc)
{
printf("Calling: operator new(%d) = ", size);
void* p = malloc(size);
if (p == NULL)
throw std::bad_alloc();
// Remember the size.
memblk* head = memblocks;
while(head->ptr)
{ ++head; }
head->ptr = p;
head->size = size;
printf("%p\n", p);
return p;
}
void operator delete(void* p) throw()
{
if (p == NULL)
return;
// Find the size.
memblk* head = find_allocation(p);
assert(head->ptr == p);
size_t size = head->size;
bool is_memory_pool_block = (size > 2000);
printf("Calling: delete %p ", p);
if (is_memory_pool_block)
printf(" <=== range: [%p - %p)\n", p, (void*)((char*)p + size));
else
printf("\n");
// Destroy contents.
std::memset(p, 0, size);
head->ptr = NULL;
head->size = 0;
free(p);
}
-------------- next part --------------
#include "Global.h"
Global obj1("global1.cc");
-------------- next part --------------
#include "Global.h"
Global obj2("global2.cc");
-------------- next part --------------
#include <cstdio>
#include "Global.h"
#include "memblk.h"
Global::~Global()
{
printf("Destructing object \"%s\" which is using memory at %p.\n",
_M_name.c_str(), _M_use_same_pool.data());
memblk* head = find_allocation(_M_use_same_pool.data());
printf("This memory belongs to a memory block "
"starting at %p with size %d.\n", head->ptr, head->size);
}
static Global obj("foo.cc");
int main()
{
printf("Starting destruction.\n");
return 0;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.tar.bz2
Type: application/x-bzip2
Size: 1612 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20041012/2dbe46c1/attachment.bz2>
More information about the Libstdc++
mailing list