简体   繁体   中英

Read access violation in custom memory pool allocator

So for learning purposes I'm trying to implement a custom memory-pool allocator. The implementation is currently very naive, but that's not the point.

When I try to allocate 8bytes (16bytes work), my program crashes at the third 8byte-allocation with the error Exception thrown: read access violation. this->**head** was 0xFFFFFFFFFFFFFFF7. Exception thrown: read access violation. this->**head** was 0xFFFFFFFFFFFFFFF7.

When I run the code outside my other project in isolation it works as expected. But I'm guessing that I might have some undefined behaviour which makes it work in isolation by plain luck. The version you see below is the code I use in isolation and the other project (where it crashes).

Any help you might be able to provide is very appreciated.

Gist of all code: https://gist.github.com/kALLEBALIK/8d9797399cf3bce8608834472d619f98

#include "FreeLinkedList.h"

class MemoryPool
{
    struct FreeHeader {};
    using  Node = FreeLinkedList<FreeHeader>::Node;
    FreeLinkedList<FreeHeader> free_list;

    size_t total_size;
    size_t used_size;
    size_t block_size;
    void* start_pointer;

    void increment();
    void decrement();

    void reset();

public:
    MemoryPool(const size_t total_size, const size_t block_size);
    ~MemoryPool();

    void* allocate(const size_t size, const size_t alignment = 0);
    void free(void* ptr);

    void print_memory_range(void* ptr, const size_t range) const;
    void print_memory() const;
};
// MemoryPool.cpp

#include "MemoryPool.h"
#include <iostream>
#include <iomanip>

void MemoryPool::increment() { this->used_size += this->block_size; }
void MemoryPool::decrement() { this->used_size -= this->block_size; }

MemoryPool::MemoryPool(const size_t total_size, const size_t block_size)
{
    this->total_size = total_size;
    this->block_size = block_size;
    this->start_pointer = malloc(this->total_size);

    reset();
}

MemoryPool::~MemoryPool()
{
    if (this->start_pointer != nullptr)
        free(this->start_pointer);
}

void MemoryPool::reset()
{
    const size_t block_count = this->total_size / this->block_size;
    for (unsigned int i = 0; i < block_count; ++i)
    {
        this->used_size = 0;
        const size_t mem_address = reinterpret_cast<size_t>(this->start_pointer) + i * block_size;
        free_list.release(reinterpret_cast<Node*>(mem_address));
    }
}

void* MemoryPool::allocate(const size_t size, const size_t alignment)
{
    Node* free_position = free_list.obtain();

    this->increment();

    return (void*)free_position;
}

void MemoryPool::free(void* ptr)
{
    this->decrement();

    free_list.release((Node*)ptr);
}

void MemoryPool::print_memory_range(void* ptr, const size_t range) const
{
    for (size_t k = 0; k < range; ++k)
    {
        printf("%02hhx ", *reinterpret_cast<unsigned char*>(reinterpret_cast<size_t>(ptr) + k));
    }
}

void MemoryPool::print_memory() const 
{
    for (size_t i = 0; i < total_size; i += block_size)
    {
        std::cout << "0x" << std::hex << std::noshowbase << std::setw(16) << std::setfill('0') << reinterpret_cast<size_t>(this->start_pointer) + i << ": ";
        print_memory_range(reinterpret_cast<void*>(reinterpret_cast<size_t>(this->start_pointer) + i), this->block_size);
        std::cout << std::endl;
    }
}
#pragma once

template <class T>
class FreeLinkedList
{
public:
    struct Node {
        T data;
        Node* next;
    };

    FreeLinkedList(FreeLinkedList&) = delete;
    FreeLinkedList()                = default;

    ~FreeLinkedList()
    {
        delete head;
    }

    void release(Node* new_node)
    {
        new_node->next = head;
        head = new_node;
    }

    Node* obtain()
    {
        if (head == nullptr)
            return nullptr;

        Node* last = head;
        head = head->next;
        return last;
    }
private:
    Node* head;
};

#include <iostream>
#include "MemoryPool.h"
#include <iomanip>

int main()
{

    struct b8
    {
        char a1 = 1;
        char a2 = 2;
        char a3 = 3;
        char a4 = 4;
        char a5 = 5;
        char a6 = 6;
        char a7 = 7;
        char a8 = 8;
    };

    struct b16
    {
        char a1 = 1;
        char a2 = 2;
        char a3 = 3;
        char a4 = 4;
        char a5 = 5;
        char a6 = 6;
        char a7 = 7;
        char a8 = 8;
        char a11 = 1;
        char a22 = 2;
        char a33 = 3;
        char a44 = 4;
        char a55 = 5;
        char a66 = 6;
        char a77 = 7;
        char a88 = 8;
    };

    std::cout << "b16 size: " << sizeof(b16) << std::endl; // 16
    std::cout << "b8  size: " << sizeof(b8)  << std::endl; //  8


    std::cout << "-------16-byte-------" << std::endl;
    MemoryPool* mp = new MemoryPool(128, 16);
    std::cout << "-before-" << std::endl;
    mp->print_memory();

    std::cout << "-first-" << std::endl;
    void* ptr11 = new(mp->allocate(16)) b16();
    mp->print_memory();

    std::cout << "-second-" << std::endl;
    void* ptr12 = new(mp->allocate(16)) b16();
    mp->print_memory();

    std::cout << "-third-" << std::endl;
    void* ptr13 = new(mp->allocate(16)) b16();
    mp->print_memory();

    std::cout << "-fourth-" << std::endl;
    void* ptr14 = new(mp->allocate(16)) b16();
    mp->print_memory();

    std::cout << "-fifth-" << std::endl;
    void* ptr15 = new(mp->allocate(16)) b16();
    mp->print_memory();

    std::cout << "-sixth-" << std::endl;
    void* ptr16 = new(mp->allocate(16)) b16();


    std::cout << "-------8-byte-------" << std::endl;
    MemoryPool* mp2 = new MemoryPool(64, 8);
    std::cout << "-before-" << std::endl;
    mp->print_memory();

    std::cout << "-first-" << std::endl;
    void* bptr11 = new(mp2->allocate(8)) b8();
    mp->print_memory();

    std::cout << "-second-" << std::endl;
    void* bptr12 = new(mp2->allocate(8)) b8();
    mp->print_memory();

    std::cout << "-third-" << std::endl;
    void* bptr13 = new(mp2->allocate(8)) b8(); // <----- Exception thrown: read access violation.this->**head** was 0xFFFFFFFFFFFFFFF7. occurred
    mp->print_memory(); 

    std::cout << "-fourth-" << std::endl;
    void* bptr14 = new(mp2->allocate(8)) b8();
    mp->print_memory();

    mp->free(ptr11);
    mp->free(ptr12);
    mp->free(ptr13);
    mp->free(ptr14);
    mp->free(ptr15);
    mp->free(ptr16);

    mp2->free(bptr11);
    mp2->free(bptr12);
    mp2->free(bptr13);
    mp2->free(bptr14);

    delete(mp);
    delete(mp2);
}

Print of visual studio error breakpoint: visual studio 断点的打印

Thanks in advance.

head doesn't appear to be initialized to anything safe to use.

Node* head = nullptr;

ought to solve that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM