https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124786
Bug ID: 124786
Summary: cannot create std::deque larger than max_size when
using mmap allocator
Product: gcc
Version: 15.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: pali at kernel dot org
Target Milestone: ---
Define own c++ allocator which directly uses the mmap() and munmap() syscalls
and always allocate just one page (if the requested allocation size does not
fit into one page then throw a c++ exception). Then use this allocator for
std::deque variable.
Example code:
#include <memory>
#include <limits>
#include <deque>
#include <cstdio>
#include <unistd.h>
#include <sys/mman.h>
template <class T>
class MmapAllocator : public std::allocator<T>
{
private:
long page_size = sysconf(_SC_PAGE_SIZE);
public:
typedef std::size_t size_type;
typedef T value_type;
MmapAllocator() = default;
template <class U> constexpr MmapAllocator(const MmapAllocator<U>&)
noexcept{}
template <typename U> struct rebind { typedef MmapAllocator<U> other;
};
using std::allocator<T>::allocator;
T* allocate(std::size_t n)
{
if (n > std::numeric_limits<std::size_t>::max() / sizeof(T))
throw std::bad_array_new_length();
if (n * sizeof(T) > std::size_t(page_size))
throw std::bad_array_new_length();
void* mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mem == MAP_FAILED)
throw std::bad_alloc();
return static_cast<T*>(mem);
}
void deallocate(T* p, std::size_t) noexcept
{
munmap(static_cast<void*>(p), page_size);
}
#ifndef WITHOUT_MMAP_MAX_SIZE
constexpr size_type max_size() const
{
return page_size;
}
#endif
};
int main() {
std::deque<int, MmapAllocator<int>> d;
printf("max_size=%zu\n", d.max_size());
for (int i = 0; i < 10000; i++)
{
try
{
d.push_front(i);
}
catch (const std::exception& e)
{
printf("push error at size=%zu\n", d.size());
throw;
}
}
printf("all OK, size=%zu\n", d.size());
return 0;
}
When compiled without any option and run it fails on error:
max_size=4096
push error at size=4096
terminate called after throwing an instance of 'std::length_error'
what(): cannot create std::deque larger than max_size()
When compiled with -DWITHOUT_MMAP_MAX_SIZE which explicitly does not define
allocator's max_size function then it runs without any error:
max_size=2305843009213693951
all OK, size=10000
It looks like that gcc's std::deque is incorrectly using the allocator's
max_size. It is able to allocate a memory and push a new element into
std::deque container with the same allocator when it is not reporting the
max_size at all. The allocator is checking that the requested size is not more
than the page size.
This looks like a bug in gcc's libstdc++ std::deque implementation.