mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
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:
Notes:
github-actions[bot]
2026-04-22 13:09:52 +00:00
Author: https://github.com/tcl3 Commit: https://github.com/LadybirdBrowser/ladybird/commit/884a0140aa7 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/9031 Reviewed-by: https://github.com/trflynn89 ✅
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user