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)
|
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);
|
void* data = nullptr;
|
||||||
if (data == MAP_FAILED)
|
// POSIX mmap rejects a zero length with EINVAL, so leave m_data null for zero-size buffers.
|
||||||
return Error::from_errno(errno);
|
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));
|
return AK::adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousBufferImpl(fd, size, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,8 +36,10 @@ AnonymousBufferImpl::~AnonymousBufferImpl()
|
|||||||
auto rc = close(m_fd);
|
auto rc = close(m_fd);
|
||||||
VERIFY(rc == 0);
|
VERIFY(rc == 0);
|
||||||
}
|
}
|
||||||
auto rc = munmap(m_data, round_up_to_power_of_two(m_size, PAGE_SIZE));
|
if (m_data) {
|
||||||
VERIFY(rc == 0);
|
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)
|
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)
|
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)
|
if (!map_handle)
|
||||||
return Error::from_windows_error();
|
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)
|
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(int fd, size_t size)
|
||||||
{
|
{
|
||||||
void* ptr = MapViewOfFile(to_handle(fd), FILE_MAP_ALL_ACCESS, 0, 0, size);
|
void* ptr = nullptr;
|
||||||
if (!ptr)
|
if (size > 0) {
|
||||||
return Error::from_windows_error();
|
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));
|
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()));
|
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);
|
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);
|
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)
|
TEST_CASE(reconstruct_from_anon_fd_shares_memory)
|
||||||
{
|
{
|
||||||
auto original = MUST(Core::AnonymousBuffer::create_with_size(128));
|
auto original = MUST(Core::AnonymousBuffer::create_with_size(128));
|
||||||
|
|||||||
Reference in New Issue
Block a user