fix: Store channel reference in CookieStore to prevent panic on unload (#39171)

CookieStore sets up a route with the resource threads to handle async
communication and needs to later unregister itself when the page
unloads. When attempting to do this in the `Drop` of CookieStore we
panic attempting to retrieve the channel via
`self.global().resource_threads()` because global is already null. This
change stores a reference to the core resource thread in the object to
send the unregister on `Drop`.

Testing: manual testing for crash fix, behavior should be unchanged

Signed-off-by: Sebastian C <sebsebmc@gmail.com>
This commit is contained in:
Sebastian C 2025-09-05 13:10:41 -05:00 committed by GitHub
parent 7ce0bd8575
commit d3809c1024
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -11,6 +11,7 @@ use cookie::{Cookie, SameSite};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc; use ipc_channel::ipc;
use ipc_channel::ipc::IpcSender;
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use itertools::Itertools; use itertools::Itertools;
use js::jsval::NullValue; use js::jsval::NullValue;
@ -46,6 +47,9 @@ pub(crate) struct CookieStore {
// Store an id so that we can send it with requests and the resource thread knows who to respond to // Store an id so that we can send it with requests and the resource thread knows who to respond to
#[no_trace] #[no_trace]
store_id: CookieStoreId, store_id: CookieStoreId,
#[ignore_malloc_size_of = "Channels are hard"]
#[no_trace]
unregister_channel: IpcSender<CoreResourceMsg>,
} }
struct CookieListener { struct CookieListener {
@ -92,16 +96,23 @@ impl CookieListener {
} }
impl CookieStore { impl CookieStore {
fn new_inherited() -> CookieStore { fn new_inherited(unregister_channel: IpcSender<CoreResourceMsg>) -> CookieStore {
CookieStore { CookieStore {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
in_flight: Default::default(), in_flight: Default::default(),
store_id: CookieStoreId::new(), store_id: CookieStoreId::new(),
unregister_channel,
} }
} }
pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<CookieStore> { pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<CookieStore> {
let store = reflect_dom_object(Box::new(CookieStore::new_inherited()), global, can_gc); let store = reflect_dom_object(
Box::new(CookieStore::new_inherited(
global.resource_threads().core_thread.clone(),
)),
global,
can_gc,
);
store.setup_route(); store.setup_route();
store store
} }
@ -567,8 +578,7 @@ impl CookieStoreMethods<crate::DomTypeHolder> for CookieStore {
impl Drop for CookieStore { impl Drop for CookieStore {
fn drop(&mut self) { fn drop(&mut self) {
let res = self let res = self
.global() .unregister_channel
.resource_threads()
.send(CoreResourceMsg::RemoveCookieListener(self.store_id)); .send(CoreResourceMsg::RemoveCookieListener(self.store_id));
if res.is_err() { if res.is_err() {
error!("Failed to send cookiestore message to resource threads"); error!("Failed to send cookiestore message to resource threads");