Почему я не получаю ошибку сегментации, когда переполняю вектор своим пользовательским распределителем? - PullRequest
1 голос
/ 16 апреля 2019

Я написал собственный LinearAllocator, который я использую с вектором.Распределитель может взять другой Распределитель в качестве параметра шаблона / конструктора, чтобы выделить его исходное хранилище.Прямо сейчас он делает первоначальное распределение с помощью std :: allocator, но когда я переполняю вектор, это не выдает ошибку.Я понимаю, что это неопределенное поведение, поэтому я не могу гарантировать segfault, но оно последовательно позволяет мне изменять 1037600 элементов с начала вектора (размером 64).

Я распечатал и изменил каждый элемент доэто дало мне ошибку:

template <class T, size_t N, class Alloc = std::allocator<uint8_t>>
class LinearAllocator
{
public:
    typedef T value_type;

    LinearAllocator()
    :m_memory{m_alloc.allocate(N)}, m_head{m_memory}
    {
    }

    template<class U>
    LinearAllocator(LinearAllocator<U, N> const& other) noexcept
    :m_memory{other.m_memory}, m_head{other.m_head}
    {}

    template<class U>
    bool operator==(LinearAllocator<U, N> const& other) const noexcept
    {
        return m_memory == other.m_memory && m_head == other.m_head;
    }

    template<class U>
    bool operator!=(LinearAllocator<U, N> const& other) const noexcept
    {
        return !(*this == other);
    }

    T* allocate(const size_t n)
    {
        uint8_t* memory = static_cast<uint8_t*>(m_memory);
        uint8_t* head = static_cast<uint8_t*>(m_head);

        if(n == 0)
        {
            return nullptr;
        }

        if(n > static_cast<size_t>(-1) / sizeof(T))
        {
            throw std::bad_array_new_length();
        }

        if(n > N) { throw std::bad_alloc(); }

        if(memory + N < head + n) { head = memory; }

        void* pv = m_head;
        head += n;
        m_head = static_cast<void*>(head);

        return static_cast<T*>(pv);
    }

    void deallocate(T* const p, size_t) const noexcept
    {}

private:
    Alloc m_alloc = Alloc();
    void* m_memory = nullptr;
    void* m_head = nullptr;
};

int main()
{
    std::vector<uint8_t, LinearAllocator<uint8_t, 64>> vec(64, 1);
    //std::vector<uint8_t> vec(65, 1);

    std::cout << (void*)vec.data() << std::endl;

    for(size_t i = 0; i < vec.size()+10000000; ++i)
    {
        std::cout << i << " " << (int)vec[i]++ << " " << (int)vec[i]<< "\n";
    }
}

Я ожидал, что это потерпит неудачу при переполнении в элементе 64, так как я думал, что это память, выделенная для кучи.Но, похоже, он потерпел неудачу в той же точке, элемент 1037663, далеко позади, где я ожидал.В частности:

$ ./run

0 1 2

1 1 2

...

1037662 0 1

1037663 0 1

Ошибка сегментации: 11

1 Ответ

1 голос
/ 16 апреля 2019

Наиболее вероятная причина заключается в том, что когда вы выделили пространство из std::allocator, он захватил достаточно памяти из ОС для хранения 1037663 элементов.Ошибка сегментации возникает, когда ОС замечает, что вы просили посмотреть адрес памяти, к которому она еще не дала разрешение вашей программе.std::allocator запросил другую память у ОС, поэтому ОС не будет замечать, когда вы превысите границы vector, пока не выйдете за пределы памяти, предоставленной для std::allocator.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...