I wanted to use a memory_pool in my derived class BackenSchemeHandlerFactory from `CefSchemeHandlerFactory` such that it does not always allocate with "new" on the heap.
What I did is the following: I included the awesome library https://github.com/foonathan/memory and used a memory_pool which I use to get some memory node (the size of the Handler it should return)
and then I wrap that thing into a CefRefPtr<handler>. Of course since the memory_pool has allocated the memory, my handler implements a special `Release()` for the CefRefPtr, to properly deallocate and delete itself trough the memory_pool which is stored in the BackenSchemeHandlerFactory.
I have a crash only when running this test code in the BackenSchemeHandlerFactory::Create function, the test code runs fine standalone:
https://github.com/gabyx/ExecutionGraph/blob/devGUI/gui/tests/src/main_MemoryPool.cpp
But the same code crashes while running my CEF Application with the EXC_BAD_ACCESS (code=EXC_I386_GPFLT).
I am really wondering what could be wrong. The deleter is called in CEF_IO_THREAD as well, so there is no ownership problem.
Is there any limitation about memory allocation in the IO Thread on the low-level calls malloc/free, alloca, or new??
If I dont use memory_pool and instead just use "new" everything works of course.
Thanks for any help!!
- Code: Select all
#include "include/cef_base.h"
using namespace foonathan::memory;
// A ref counted class (CefRefPtr from Chromium Embedded Framework)
struct A : CefBaseRefCounted
{
template<typename D>
A(int a, D&& d)
: m_a{a}, deleter(d) {}
~A() { std::cout << "dtor A :" << m_a[0] << std::endl; }
int m_a[100];
std::function<void(A*)> deleter; // Wrap here the deleter to delete over the pool
void AddRef() const override { m_refCount.AddRef(); }
bool Release() const override
{
if(m_refCount.Release())
{
deleter(const_cast<A*>(this));
return true;
}
return false;
}
bool HasOneRef() const override { return m_refCount.HasOneRef(); }
CefRefCount m_refCount;
};
MY_TEST(MemoryPool, Test1)
{
using RawAllocator = memory_pool<>;
using Ptr = CefRefPtr<A>;
using RawPtr = std::unique_ptr<A, allocator_deallocator<A, RawAllocator>>;
RawAllocator pool(sizeof(A), sizeof(A) * 10);
std::vector<Ptr> vec;
for(auto i = 0; i < 30000; ++i)
{
auto memory = pool.allocate_node(); // CRASHES here and third call
// raw_ptr deallocates memory in case of constructor exception
RawPtr result(static_cast<A*>(memory), {pool});
// call constructor (placement new)
::new(memory) A(i, [&pool](auto* p) { allocator_deleter<A, RawAllocator>{pool}(p); });
// pass ownership to return value CefRefPtr which will use the internal BackendResourceHandler::m_deleter
std::cout << "allocated " << i << std::endl;
vec.emplace_back(Ptr(result.release()));
}
std::shuffle(vec.begin(), vec.end(), std::mt19937{});
}
int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}