std container with custom allocator crash at class creation

65 views Asked by At

I have a custom allocator written in C that works without problem. I tried to insert it in a c++ project and I is working with std containers as long as the container is not global or in a class. because the allocator needs to be initialized before any used

Init_allocator(maxPageSize);
int * p = Allocate(sizeof(int) * 100);
Free(p);
Clear_allocator();

Let me show the C++ part:

template<typename  T>
struct MyAllocator
{
    typedef T value_type;

    MyAllocator() = default;
    template<typename  U>
    constexpr MyAllocator(const MyAllocator<U>&) noexcept {}
    [[nodiscard]] T * allocate(std::size_t n)
    {
        if(n > std::numeric_limits<std::size_t>::max() / sizeof(T))
        {
            throw std::bad_array_new_length();
        }

        return static_cast<T*>(Allocate(sizeof(T) * n));
    }

    void deallocate(T * p, std::size_t n) noexcept
    {
        Free((void *)p);
    }

};

template<typename T>
using UnorderedMap = std::unordered_map<T, U, std::hash<T>, std::equal_to<T>,MyAllocator<std::pair<T, U>>>;

So if I use it inside a function there is no problem

main(){
    Init_allocator(maxPageSize);
    UnorderedMap<std::string, int> myMap;
    myMap["one"] = 1;
    Clear_allocator();
}

but when I do

class A{
    public:
        UnorderedMap<std::string, int> mMap;
};
main(){
    Init_allocator(maxPageSize);
    A myClass;
    Clear_allocator();
}

then it crashed and the crash is in the function allocate. I understand that the function been called before the call of Init_allocator so some variable have dirty values. It seems like the class is initialized before. This is where I am lost. My init will call the malloc and create different pages and than Allocate is just a free list. Is there a solution or do I have to give up on this allocator?

EDIT: adding the allocator code and pointing where it crashed

void * Allocate(size_t size, size_t alignment, size_t id, const char * file, int line)
{
    if(alignment == 0)
    {
        alignment = gDefaultAlignment;
    }

    AllocationGroup * grp = &gAllocGrp[id];
    MemoryPage * page = NULL;
    size_t alignShift = alignment < 2 ? 0 : alignment * 2;
    size_t size_ = MIN_META_SIZE - 1 + size + alignShift;

    if(size_ >= grp->pageSize) //CRASH HERE with Exception has orrured Exception 0xc00000005 encountered at adress xxxx: Accesss violation reading loacation xxxx
    {
        LOGC(eFATAL, gTag, gTagColor, "Cannot allocat that much");
    
    }

    LockMutex(&grp->mutex);
    size_t pageCount = grp->pageCount;
    UnlockMutex(&grp->mutex);

    for(size_t i = 0; i < pageCount; ++i)
    {
        LockMutex(&grp->pages[i].mutex);
        size_t bigestFree = grp->pages[i].bigestFree;
        UnlockMutex(&grp->pages[i].mutex);

        if(bigestFree >= size_)
        {
            page = &grp->pages[i];
            break;
        }
    }

    if(page == NULL)
    {
        if(pageCount < MAX_PAGES)
        {
            createPage(grp);
            page = &grp->pages[grp->pageCount - 1];
        }
        else
        {
            LOGC(eFATAL, gTag, gTagColor, "Out of Memory!");
        }
    }

    void * result = AllocateFromPage(page, size_, alignment, file, line);
    struct BlockHeader * bH = getBlockHeader(result);
    bH->payloadSize = size;
    return result;
}

I will add that it doesn't not crash with std::vector, unordered_set and string. only unordered_map crashed.

Edit 2: I dont' really understand what even the code is relevant, I think it is more theorical than a bug. I wrote this in allocate to test

void * Allocate(...)
{
    fprintf(stderr, "Allocator called\n");
    return;
}

And it showed that the allocator is called before main() meaning even if there is not bug or there is a bug it doesnt matter as Allocate is called before initialization. then added in allocate

void * Allocate(...)
{
    if(global_initialize == 0)
    {
          InitAllocator(/*init with default values*/);
    }
    ...
}

after that it worked but now Clear_allocator(); is a new issue as the destructor of std::unordered_map will call Free() after main() which already call Clear_allocator();

0

There are 0 answers