From d5be18617ed97b22281aa90cbb8976f7260e3615 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 26 Feb 2025 20:40:10 -0500 Subject: [PATCH] LibWeb: Ensure EventHandler visits its mouse selection target We hold a raw pointer to the mouse selection target, which is a mixin- style class inherited only by JS::Cell classes. By not visiting this object, we sometime had a dangling reference to it after it had been garbage collected. --- Libraries/LibWeb/DOM/EditingHostManager.h | 5 ++- Libraries/LibWeb/DOM/InputEventsTarget.h | 2 + .../LibWeb/HTML/FormAssociatedElement.cpp | 5 +++ Libraries/LibWeb/HTML/FormAssociatedElement.h | 5 ++- Libraries/LibWeb/Page/EventHandler.cpp | 3 ++ .../UIEvents/gc-mouse-selection-target.txt | 1 + .../UIEvents/gc-mouse-selection-target.html | 37 +++++++++++++++++++ 7 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/UIEvents/gc-mouse-selection-target.txt create mode 100644 Tests/LibWeb/Text/input/UIEvents/gc-mouse-selection-target.html diff --git a/Libraries/LibWeb/DOM/EditingHostManager.h b/Libraries/LibWeb/DOM/EditingHostManager.h index 283aca0e82..dd6dc179bf 100644 --- a/Libraries/LibWeb/DOM/EditingHostManager.h +++ b/Libraries/LibWeb/DOM/EditingHostManager.h @@ -14,7 +14,8 @@ namespace Web::DOM { -class EditingHostManager : public JS::Cell +class EditingHostManager + : public JS::Cell , public InputEventsTarget { GC_CELL(EditingHostManager, JS::Cell); GC_DECLARE_ALLOCATOR(EditingHostManager); @@ -45,6 +46,8 @@ public: private: EditingHostManager(GC::Ref); + virtual GC::Ref as_cell() override { return *this; } + GC::Ref m_document; GC::Ptr m_active_contenteditable_element; }; diff --git a/Libraries/LibWeb/DOM/InputEventsTarget.h b/Libraries/LibWeb/DOM/InputEventsTarget.h index 95a32b3dd6..58b007fb5c 100644 --- a/Libraries/LibWeb/DOM/InputEventsTarget.h +++ b/Libraries/LibWeb/DOM/InputEventsTarget.h @@ -15,6 +15,8 @@ class InputEventsTarget { public: virtual ~InputEventsTarget() = default; + virtual GC::Ref as_cell() = 0; + virtual void handle_insert(String const&) = 0; virtual void handle_return_key() = 0; diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp index 0887c8824e..3bc1cd8f39 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp @@ -969,4 +969,9 @@ GC::Ptr FormAssociatedTextControlElement::cursor_position() const return nullptr; } +GC::Ref FormAssociatedTextControlElement::as_cell() +{ + return form_associated_element_to_html_element(); +} + } diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.h b/Libraries/LibWeb/HTML/FormAssociatedElement.h index 6536283174..b9975bc42c 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.h +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.h @@ -160,7 +160,8 @@ enum class SelectionSource { DOM, }; -class FormAssociatedTextControlElement : public FormAssociatedElement +class FormAssociatedTextControlElement + : public FormAssociatedElement , public InputEventsTarget { public: // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value @@ -231,6 +232,8 @@ protected: void relevant_value_was_changed(); private: + virtual GC::Ref as_cell() override; + void collapse_selection_to_offset(size_t); void selection_was_changed(); diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 4076719dda..2a19aaa202 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -1375,6 +1375,9 @@ void EventHandler::visit_edges(JS::Cell::Visitor& visitor) const { m_drag_and_drop_event_handler->visit_edges(visitor); visitor.visit(m_mouse_event_tracking_paintable); + + if (m_mouse_selection_target) + visitor.visit(m_mouse_selection_target->as_cell()); } Unicode::Segmenter& EventHandler::word_segmenter() diff --git a/Tests/LibWeb/Text/expected/UIEvents/gc-mouse-selection-target.txt b/Tests/LibWeb/Text/expected/UIEvents/gc-mouse-selection-target.txt new file mode 100644 index 0000000000..aaecaf93c4 --- /dev/null +++ b/Tests/LibWeb/Text/expected/UIEvents/gc-mouse-selection-target.txt @@ -0,0 +1 @@ +PASS (didn't crash) diff --git a/Tests/LibWeb/Text/input/UIEvents/gc-mouse-selection-target.html b/Tests/LibWeb/Text/input/UIEvents/gc-mouse-selection-target.html new file mode 100644 index 0000000000..a8ff1965de --- /dev/null +++ b/Tests/LibWeb/Text/input/UIEvents/gc-mouse-selection-target.html @@ -0,0 +1,37 @@ + + + +