From 26de1ca6006fee625a179ca08fe05804d4a10f98 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 4 Jun 2026 10:40:53 +0200 Subject: [PATCH] WebContent: Terminate immediately on client disconnect Use Core::Process::terminate_immediately() when the UI process goes away or a sync IPC request fails because the client disconnected. This avoids running exit-time destructors during WebContent shutdown. Enable -Wexit-time-destructors for the WebContent executable and service target, then convert the existing warning sites to permanent process lifetime storage. --- Services/WebContent/CMakeLists.txt | 2 ++ Services/WebContent/ConnectionFromClient.cpp | 3 +- Services/WebContent/PageClient.cpp | 21 +++++++------- Services/WebContent/WebDriverConnection.cpp | 5 ++-- Services/WebContent/WebUIConnection.cpp | 29 +++++++++++++++----- Services/WebContent/main.cpp | 2 +- 6 files changed, 41 insertions(+), 21 deletions(-) diff --git a/Services/WebContent/CMakeLists.txt b/Services/WebContent/CMakeLists.txt index 835b3865f0..f353ca14be 100644 --- a/Services/WebContent/CMakeLists.txt +++ b/Services/WebContent/CMakeLists.txt @@ -34,10 +34,12 @@ target_include_directories(webcontentservice PUBLIC $:-Wexit-time-destructors>) add_executable(WebContent main.cpp) target_link_libraries(WebContent PRIVATE webcontentservice LibURL) +target_compile_options(WebContent PRIVATE $<$:-Wexit-time-destructors>) if(WIN32) ladybird_windows_bin(WebContent CONSOLE) diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index a8439c939d..402995b57e 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -100,7 +101,7 @@ void ConnectionFromClient::did_destroy_compositor_context(Web::Compositor::Compo void ConnectionFromClient::die() { - _exit(0); + Core::Process::terminate_immediately(0); } Messages::WebContentServer::InitTransportResponse ConnectionFromClient::init_transport([[maybe_unused]] int peer_pid) diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 29d0023c21..c691df4b03 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -605,7 +606,7 @@ HTTP::Cookie::VersionedCookie PageClient::page_did_request_cookie(URL::URL const auto response = client().send_sync_but_allow_failure(m_id, url, source); if (!response) { dbgln("WebContent client disconnected during DidRequestCookie. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } return response->take_cookie(); } @@ -615,7 +616,7 @@ void PageClient::page_did_set_cookie(URL::URL const& url, HTTP::Cookie::ParsedCo auto response = client().send_sync_but_allow_failure(url, cookie, source); if (!response) { dbgln("WebContent client disconnected during DidSetCookie. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } } @@ -647,7 +648,7 @@ bool PageClient::page_did_is_known_hsts_host(String const& domain) auto response = client().send_sync_but_allow_failure(domain); if (!response) { dbgln("WebContent client disconnected during DidIsKnownHstsHost. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } return response->result(); } @@ -657,7 +658,7 @@ Optional PageClient::page_did_request_storage_item(Web::StorageAPI::Stor auto response = client().send_sync_but_allow_failure(storage_endpoint, storage_key, bottle_key); if (!response) { dbgln("WebContent client disconnected during DidRequestStorageItem. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } return response->take_value(); } @@ -667,7 +668,7 @@ WebView::StorageSetResult PageClient::page_did_set_storage_item(Web::StorageAPI: auto response = client().send_sync_but_allow_failure(storage_endpoint, storage_key, bottle_key, value); if (!response) { dbgln("WebContent client disconnected during DidSetStorageItem. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } return response->result(); } @@ -677,7 +678,7 @@ void PageClient::page_did_remove_storage_item(Web::StorageAPI::StorageEndpointTy auto response = client().send_sync_but_allow_failure(storage_endpoint, storage_key, bottle_key); if (!response) { dbgln("WebContent client disconnected during DidRemoveStorageItem. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } } @@ -686,7 +687,7 @@ Vector PageClient::page_did_request_storage_keys(Web::StorageAPI::Storag auto response = client().send_sync_but_allow_failure(storage_endpoint, storage_key); if (!response) { dbgln("WebContent client disconnected during DidRequestStorageKeys. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } return response->take_keys(); } @@ -696,7 +697,7 @@ void PageClient::page_did_clear_storage(Web::StorageAPI::StorageEndpointType sto auto response = client().send_sync_but_allow_failure(storage_endpoint, storage_key); if (!response) { dbgln("WebContent client disconnected during DidClearStorage. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } } @@ -720,7 +721,7 @@ PageClient::NewWebViewResult PageClient::page_did_request_new_web_view(Web::HTML auto response = client().send_sync_but_allow_failure(m_id, activate_tab, hints); if (!response) { dbgln("WebContent client disconnected during DidRequestNewWebView. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } auto& new_client = m_owner.create_page(response->new_page_id()); @@ -819,7 +820,7 @@ Web::HTML::WorkerAgentId PageClient::start_worker_agent(Web::HTML::WorkerAgentSt auto response = client().send_sync_but_allow_failure(m_id, move(request)); if (!response) { dbgln("WebContent client disconnected during StartWorkerAgent. Exiting peacefully."); - exit(0); + Core::Process::terminate_immediately(0); } return response->agent_id(); diff --git a/Services/WebContent/WebDriverConnection.cpp b/Services/WebContent/WebDriverConnection.cpp index e2e05476a1..bf543ab463 100644 --- a/Services/WebContent/WebDriverConnection.cpp +++ b/Services/WebContent/WebDriverConnection.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -2667,11 +2668,11 @@ ErrorOr WebDriverConnection::ensure_current_top_lev // https://w3c.github.io/webdriver/#dfn-get-the-prompt-handler Web::WebDriver::PromptHandlerConfiguration WebDriverConnection::get_the_prompt_handler(Web::WebDriver::PromptType type) const { - static Web::WebDriver::UserPromptHandler::ValueType empty_user_prompt_handler; + static NeverDestroyed empty_user_prompt_handler; auto const& user_prompt_handler = Web::WebDriver::user_prompt_handler(); // 1. If the user prompt handler is null, let handlers be an empty map. Otherwise let handlers be user prompt handler. - auto const& handlers = user_prompt_handler.has_value() ? *user_prompt_handler : empty_user_prompt_handler; + auto const& handlers = user_prompt_handler.has_value() ? *user_prompt_handler : *empty_user_prompt_handler; // 2. If handlers contains type return handlers[type]. if (auto handler = handlers.get(type); handler.has_value()) diff --git a/Services/WebContent/WebUIConnection.cpp b/Services/WebContent/WebUIConnection.cpp index 279d818af9..bea7f51e61 100644 --- a/Services/WebContent/WebUIConnection.cpp +++ b/Services/WebContent/WebUIConnection.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -17,9 +18,23 @@ namespace WebContent { -static auto LADYBIRD_PROPERTY = JS::PropertyKey { "ladybird"_utf16_fly_string }; -static auto WEB_UI_LOADED_EVENT = "WebUILoaded"_fly_string; -static auto WEB_UI_MESSAGE_EVENT = "WebUIMessage"_fly_string; +static JS::PropertyKey const& ladybird_property() +{ + static NeverDestroyed property { "ladybird"_utf16_fly_string }; + return *property; +} + +static FlyString const& web_ui_loaded_event() +{ + static NeverDestroyed event { "WebUILoaded"_fly_string }; + return *event; +} + +static FlyString const& web_ui_message_event() +{ + static NeverDestroyed event { "WebUIMessage"_fly_string }; + return *event; +} ErrorOr> WebUIConnection::connect(IPC::TransportHandle handle, Web::DOM::Document& document) { @@ -32,10 +47,10 @@ WebUIConnection::WebUIConnection(NonnullOwnPtr transport, Web::D , m_document(document) { auto& realm = m_document->realm(); - m_document->window()->define_direct_property(LADYBIRD_PROPERTY, realm.create(realm), JS::default_attributes); + m_document->window()->define_direct_property(ladybird_property(), realm.create(realm), JS::default_attributes); Web::HTML::queue_a_task(Web::HTML::Task::Source::Unspecified, nullptr, m_document, GC::create_function(realm.heap(), [&document = *m_document]() { - document.dispatch_event(Web::DOM::Event::create(document.realm(), WEB_UI_LOADED_EVENT)); + document.dispatch_event(Web::DOM::Event::create(document.realm(), web_ui_loaded_event())); })); } @@ -44,7 +59,7 @@ WebUIConnection::~WebUIConnection() if (!m_document->window()) return; - (void)m_document->window()->internal_delete(LADYBIRD_PROPERTY); + (void)m_document->window()->internal_delete(ladybird_property()); } void WebUIConnection::visit_edges(JS::Cell::Visitor& visitor) @@ -73,7 +88,7 @@ void WebUIConnection::send_message(String name, JsonValue data) Web::Bindings::CustomEventInit event_init {}; event_init.detail = serialized_detail.value(); - m_document->dispatch_event(Web::DOM::CustomEvent::create(realm, WEB_UI_MESSAGE_EVENT, event_init)); + m_document->dispatch_event(Web::DOM::CustomEvent::create(realm, web_ui_message_event(), event_init)); } void WebUIConnection::received_message_from_web_ui(String const& name, JS::Value data) diff --git a/Services/WebContent/main.cpp b/Services/WebContent/main.cpp index 37fde978fd..3b3cc3a04d 100644 --- a/Services/WebContent/main.cpp +++ b/Services/WebContent/main.cpp @@ -84,7 +84,7 @@ static void crash_signal_handler(int signo) } warnln("\n\033[31;1mCRASH\033[0m: Received signal {} ({})", name, signo); dump_backtrace(2, 100); - exit(128 + signo); + Core::Process::terminate_immediately(128 + signo); } static void install_crash_signal_handlers()