Home > Back-end >  Vector of structs containing allocation pointers is failing to destruct
Vector of structs containing allocation pointers is failing to destruct

Time:11-30

In my project I use a class for paged memory allocation. This class uses a struct to store all of its allocations:

enum PageStatus : uint_fast8_t {    //!< possible use stati of an allocated page
    PAGE_STATUS_INVALID     = 0b00,
    PAGE_STATUS_FREE        = 0b01, //!< the page is free
    PAGE_STATUS_USED        = 0b10, //!< the page is (partially) used
};

struct PhysicalPage {    //!< represents a page that has been allocated
    char* pData;         //!< pointer to the allocation
    PageStatus status;   //!< status of the allocation
};

These PhysicalPages are stored in a vector std::vector<PhysicalPage> physicalAllocations {};. During runtime pages are added to the vector and some may be removed. During the removal the last element is popped and the memory is returned using delete page.pData. However a problem occurs when the allocator class reaches end of life and gets deallocated from the stack. When pyhsicalAllocations's vector destructor is called it tries to destruct not only the elements themself but also the reserved memory (which the vector keeps as a buffer for when the size is changed). That causes invalid memory pointers to be deleted, stopping program execution:

double free or corruption (!prev)
Signal: SIGABRT (Aborted)

It's probably also worth mentioning that allocations are done in chunks larger than pages, which means that only one in every x pointers are actually valid allocations. All other pointers are just offsets from the actual memory locations.

To prevent the error from occurring I tried:

deleting manually (this is a bit overcomplicated due to chunked allocation)

for (size_t i = physicalAllocations.size(); 0 < i; i -= 1 << allocationChunkSize) {
    delete physicalAllocations[i - (1 << allocationChunkSize)].pData;
    for (size_t a = 0; a < 1 << allocationChunkSize; a  )
        physicalAllocations.pop_back();
}

clearing the vector

physicalAllocations.clear();

swapping for a clear vector

std::vector<PhysicalPage>(0).swap(physicalAllocations);

of which none worked.

I've been working on this problem for a lot longer that I would like to admit and your help is very much appreciated. Thanks!

CodePudding user response:

std::shared_ptr<char[]> pData and its aliasing constructor (8) might help. (that might even allow to get rid of PageStatus).

It would look something like:

constexpr std::size_t page_size = 6;

struct PhysicalPage {
    std::shared_ptr<char[]> pData;
};

int main()
{
    std::vector<PhysicalPage> pages;
    {
        std::shared_ptr<char[]> big_alloc = std::unique_ptr<char[]>(new char[42]{"hello world. 4 8 15 16 23 42"});

        for (std::size_t i = 0; i != 42 / page_size;   i) {
            pages.push_back(PhysicalPage{std::shared_ptr<char[]>{big_alloc, big_alloc.get()   i * page_size}});
        }
    }
    pages.erase(pages.begin());
    pages.erase(pages.begin()   2);    
    for (auto& p : pages) {
        std::cout << std::string_view(p.pData.get(), page_size) << std::endl;
    }
}

Demo

  • Related