foonathan / memory

STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.
https://memory.foonathan.net
zlib License
1.5k stars 194 forks source link

Calling pure virtual function. #180

Closed mcourteaux closed 7 months ago

mcourteaux commented 7 months ago

When making a Debug build (cmake) of my project using foonathan::memory under G++-12, I got an exception attempting to call a pure virtual function. More specifically, I was having an memory::any_allocator_reference to a memory::new_allocator on which I called .deallocate_node(), which somehow attempts to call deallocate_node on the base_allocator. Here is the relevant gdb backtrace:


pure virtual method called
terminate called without an active exception

Thread 7 "Worker 01" received signal SIGABRT, Aborted.
[Switching to Thread 0x7fffeec39640 (LWP 1122096)]
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737199183424) at ./nptl/pthread_kill.c:44
44  ./nptl/pthread_kill.c: No such file or directory.
(gdb) bt
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737199183424) at /home/martijn/zec/SilverNode/build_deb/nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=140737199183424) at /home/martijn/zec/SilverNode/build_deb/nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=140737199183424, signo=6) at /home/martijn/zec/SilverNode/build_deb/nptl/pthread_kill.c:89
#4  0x00007ffff72287f3 in __GI_abort ()
    at /home/martijn/zec/SilverNode/build_deb/stdlib/abort.c:79
#9  0x0000555555bc338d in foonathan::memory::reference_storage<foonathan::memory::any_allocator>::base_allocator::deallocate_node(void*, unsigned long, unsigned long)
    (this=0x7fffd82e29c8, node=0x7fffd82e29c0, size=256, alignment=8)
    at /home/martijn/zec/NeonRAW/ext/memory/include/foonathan/memory/allocator_storage.hpp:639
#10 0x0000555555c14f09 in foonathan::memory::traits_detail::deallocate_node<foonathan::memory::reference_storage<foonathan::memory::any_allocator>::base_allocator>(foonathan::memory::traits_detail::full_concept, foonathan::memory::reference_storage<foonathan::memory::any_allocator>::base_allocator&, void*, unsigned long, unsigned long) (alloc=..., ptr=0x7fffd82e29c0, size=256, alignment=8)
    at /home/martijn/zec/NeonRAW/ext/memory/include/foonathan/memory/allocator_traits.hpp:197
#11 0x0000555555c05601 in foonathan::memory::allocator_traits<foonathan::memory::reference_storage<foonathan::memory::any_allocator>::base_allocator>::deallocate_node(foonathan::memory::reference_storage<foonathan::memory::any_allocator>::base_allocator&, void*, unsigned long, unsigned long) (state=..., node=0x7fffd82e29c0, size=256, alignment=8)
    at /home/martijn/zec/NeonRAW/ext/memory/include/foonathan/memory/allocator_traits.hpp:324
#12 0x0000555555bf2672 in foonathan::memory::allocator_storage<foonathan::memory::reference_storage<foonathan::memory::any_allocator>, foonathan::memory::no_mutex>::deallocate_node(void*, unsigned long, unsigned long) (this=0x7fffd82e29c8, ptr=0x7fffd82e29c0, size=256, alignment=8)
    at /home/martijn/zec/NeonRAW/ext/memory/include/foonathan/memory/allocator_storage.hpp:194

I spent a lot of time looking at the code, but all of the one-liner redirects and traits makes it impossible for me to figure out what's going on.

mcourteaux commented 7 months ago

Okay it's my bad. The small repro here is like this:


struct Foo {
   void destroy_and_dealloc();
   memory::any_allocator_reference alloc;
}

void Foo::destroy_and_dealloc() {
    memory::any_allocator_reference copy_ref = alloc; // copy ref before calling destructor.
    this->~Foo();
    alloc.deallocate_node(this, sizeof(Foo), alignof(Foo));
}

I accidentally still used the alloc member field instead of my safe copy.