0

Ok, I'm having a bit of a problem using the boost::fast_pool_allocator.

The code I have is working for the first couple of calls to fast_pool_allocator::allocate(1), but then is failing with the following message:

Unhandled exception at 0x000000013fd0fe2d in Engine.exe: 0xC00000005: Access violation reading location 0x0000000000ffffff

Call stack:

Engine.exe!boost::simple_segregated_storage<unsigned __int64>::malloc()  Line 104
Engine.exe!boost::pool<boost::default_user_allocator_new_delete>::malloc()  Line 223 
Engine.exe!boost::singleton_pool<boost::fast_pool_allocator_tag,128,boost::default_user_allocator_new_delete,boost::details::pool::win32_mutex,32>::malloc()  Line 59
Engine.exe!boost::fast_pool_allocator<EventDataSize,boost::default_user_allocator_new_delete,boost::details::pool::win32_mutex,32>::allocate(const unsigned __int64 n)  Line 229
Engine.exe!IEventData::operator new(unsigned __int64 size)  Line 46
etc...  

The line of boost code in question appears to be right where the allocators storage mechanism is about to return the next free chunk, and is removing it from the list of free chunks

void * malloc()
{
  void * const ret = first;

  // Increment the "first" pointer to point to the next chunk
  first = nextof(first); // <--- This is the line that is failing.
  return ret;
}

My code looks like this:

class EventDataSize
{
private:
    U8 dummyField[128];
};

class IEventData
{    
public:    
    void* operator new(size_t size)
    {       
        void* ptr = boost::fast_pool_allocator<EventDataSize>::allocate(1);
        if (!ptr)
            throw std::bad_alloc();
        return ptr;
    }

    void operator delete(void* ptr)
    {
        boost::fast_pool_allocator<EventDataSize>::deallocate((EventDataSize*)ptr, 1);
    }

// etc...
}

As you can see, I am attempting to use this EventDataSize class as a dummy, so that any class which inherits from IEventData will be allocated the same size (128 bytes for example), allowing the pool allocator to work happily with inheritance.

I am using exactly the same pattern elsewhere to implement operator new with other base classes, and they don't seem to be suffering the same issue.

Curiously, if I alter the array size of EventDataSize::dummyField the problem disappears (or at least, it hasn't appeared yet), but I'm not comfortable with such a substandard solution... I want to know why this allocator is doing what it is doing, what I'm doing wrong, and how I can gracefully fix it!

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
Tom Cutts
  • 33
  • 3

2 Answers2

3

I realised, because I had another base class IControl, using the same pattern, and using its own ControlSize dummy (also of 128 bytes) that both fast_pool_allocators were using the same pool object under the hood.

One of my subclasses of IControl was bigger than 128 bytes, however. It was therefore getting allocated no problem, but then overwritting the pools linked list of free chunks.

Essentially, it was exactly the problem Oo Tiib was talking about, but shifted to a slightly different section of code.

I fixed up the code in both places as Oo Tiib showed and bish-bash-bosh, it works like a charm!

Tom Cutts
  • 33
  • 3
2

Always test that your theories (whatever they are) hold. You seem to have a theory that 128 bytes are good enough for any IEventData, so you may ignore the size? Go ahead and test it:

void* operator new(size_t size)
{
    if ( size > sizeof( EventDataSize ) )
    {
       throw std::runtime_error("crappy idea, pal");
    }
    void* ptr = boost::fast_pool_allocator<EventDataSize>::allocate(1);
    if (!ptr)
        throw std::bad_alloc();
    return ptr;
}

For me it feels likely that there is event data bigger than 128 bytes and so it screws up the stuff in pool allocator's pool.

Öö Tiib
  • 10,809
  • 25
  • 44
  • Thanks for the response Oo Tiib... I'm gonna use your extra bit of code, because its a good idea anyway. Unfortunately, I have currently only one concrete class inheriting from IEventData, and it is only 8 bytes in size. As far as I can tell, its not any IEventData subclass thats going wrong, it is the actual allocator itself. Does anyone know of any resource/tutorial that explains all possible usage of boost::fast_pool_allocator, particularly with regard to overloading operator new, and inheritance? Thanks! – Tom Cutts Sep 10 '12 at 15:47
  • Actually - I realised what was going on, and your answer gave me a massive hint! Details below! – Tom Cutts Sep 10 '12 at 17:27