LibCore: Allow zero-size AnonymousBuffer creation

Previously, `AnonymousBuffer::create_with_size(0)` returned an error
because POSIX `mmap` rejects a zero length with `EINVAL`, and Windows
`CreateFileMapping` rejects a zero maximum size for an anonymous
mapping. This caused a crash when using `--headless=text` with zero
size pages like `about:blank`.
This commit is contained in:
Tim Ledbetter
2026-04-22 10:34:21 +01:00
committed by Tim Flynn
parent 1b5f85da1e
commit 884a0140aa
Notes: github-actions[bot] 2026-04-22 13:09:52 +00:00
4 changed files with 37 additions and 10 deletions

View File

@@ -20,9 +20,13 @@ ErrorOr<AnonymousBuffer> AnonymousBuffer::create_with_size(size_t size)
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(int fd, size_t size)
{
auto* data = mmap(nullptr, round_up_to_power_of_two(size, PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
return Error::from_errno(errno);
void* data = nullptr;
// POSIX mmap rejects a zero length with EINVAL, so leave m_data null for zero-size buffers.
if (size > 0) {
data = mmap(nullptr, round_up_to_power_of_two(size, PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
return Error::from_errno(errno);
}
return AK::adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousBufferImpl(fd, size, data));
}
@@ -32,8 +36,10 @@ AnonymousBufferImpl::~AnonymousBufferImpl()
auto rc = close(m_fd);
VERIFY(rc == 0);
}
auto rc = munmap(m_data, round_up_to_power_of_two(m_size, PAGE_SIZE));
VERIFY(rc == 0);
if (m_data) {
auto rc = munmap(m_data, round_up_to_power_of_two(m_size, PAGE_SIZE));
VERIFY(rc == 0);
}
}
ErrorOr<AnonymousBuffer> AnonymousBuffer::create_from_anon_fd(int fd, size_t size)

View File

@@ -30,7 +30,10 @@ AnonymousBufferImpl::~AnonymousBufferImpl()
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size)
{
HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size >> 32, size & 0xFFFFFFFF, NULL);
// CreateFileMapping rejects a zero-size mapping backed by INVALID_HANDLE_VALUE, so allocate at least one byte and
// track the logical size separately.
auto map_size = max(size, 1uz);
HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, map_size >> 32, map_size & 0xFFFFFFFF, NULL);
if (!map_handle)
return Error::from_windows_error();
@@ -39,9 +42,12 @@ ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t s
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(int fd, size_t size)
{
void* ptr = MapViewOfFile(to_handle(fd), FILE_MAP_ALL_ACCESS, 0, 0, size);
if (!ptr)
return Error::from_windows_error();
void* ptr = nullptr;
if (size > 0) {
ptr = MapViewOfFile(to_handle(fd), FILE_MAP_ALL_ACCESS, 0, 0, size);
if (!ptr)
return Error::from_windows_error();
}
return adopt_ref(*new AnonymousBufferImpl(fd, size, ptr));
}

View File

@@ -1070,7 +1070,8 @@ void ConnectionFromClient::request_internal_page_info(u64 page_id, WebView::Page
}
auto buffer = MUST(Core::AnonymousBuffer::create_with_size(builder.length()));
memcpy(buffer.data<void>(), builder.string_view().characters_without_null_termination(), builder.length());
if (builder.length() > 0)
memcpy(buffer.data<void>(), builder.string_view().characters_without_null_termination(), builder.length());
async_did_get_internal_page_info(page_id, type, buffer);
}

View File

@@ -42,6 +42,20 @@ TEST_CASE(read_and_write_contents)
EXPECT_EQ(read_back, payload);
}
TEST_CASE(create_with_zero_size)
{
auto buffer = MUST(Core::AnonymousBuffer::create_with_size(0));
EXPECT(buffer.is_valid());
EXPECT_EQ(buffer.size(), 0u);
EXPECT(buffer.bytes().is_empty());
auto fd = MUST(Core::System::dup(buffer.fd()));
auto mirror = MUST(Core::AnonymousBuffer::create_from_anon_fd(fd, 0));
EXPECT(mirror.is_valid());
EXPECT_EQ(mirror.size(), 0u);
EXPECT(mirror.bytes().is_empty());
}
TEST_CASE(reconstruct_from_anon_fd_shares_memory)
{
auto original = MUST(Core::AnonymousBuffer::create_with_size(128));