为什么当我使用自定义分配器溢出向量时没有出现分段错误?



我编写了一个自定义的线性分配器,我正在与向量一起使用。分配器可以将另一个分配器作为模板/构造函数参数来分配其初始存储。现在它使用 std::分配器进行初始分配就很好了,但是当我溢出向量时,它不会给出错误。我知道这是未定义的行为,所以我不能保证段错误,但它始终允许我从向量(大小为 64(的开头修改 1037600 个元素。

我打印并修改了每个元素,直到它给我一个错误:

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,远远超出了我的预期。具体说来:

$ ./运行

0 1 2

1

1 2

1037662 0 1

1037663 0 1

分段错误:11

最可能的原因是当你从std::allocator分配空间时,它从操作系统中获取了足够的内存来容纳1037663元素。 当操作系统注意到你要求查看尚未授予程序访问权限的内存地址时,会发生分段错误。 std::allocator已要求操作系统提供其他内存,因此操作系统不会注意到何时超出vector的边界,直到您超出提供给std::allocator的内存范围。

最新更新