Browse Source

LibWeb: Weakly store a reference to the Window object in timer tasks

This prevents a crash when refreshing or navigating away from the Acid3
test page while it is actively running.
Timothy Flynn 3 years ago
parent
commit
430559ea51
2 changed files with 13 additions and 5 deletions
  1. 11 5
      Userland/Libraries/LibWeb/HTML/Window.cpp
  2. 2 0
      Userland/Libraries/LibWeb/HTML/Window.h

+ 11 - 5
Userland/Libraries/LibWeb/HTML/Window.cpp

@@ -200,7 +200,11 @@ i32 Window::run_timer_initialization_steps(Bindings::TimerHandler handler, i32 t
     // 8. Assert: initiating script is not null, since this algorithm is always called from some script.
 
     // 9. Let task be a task that runs the following substeps:
-    auto task = [window = NonnullRefPtr(*this), handler = move(handler), timeout, arguments = move(arguments), repeat, id]() mutable {
+    auto task = [weak_window = make_weak_ptr(), handler = move(handler), timeout, arguments = move(arguments), repeat, id]() mutable {
+        auto window = weak_window.strong_ref();
+        if (!window)
+            return;
+
         // 1. If id does not exist in global's map of active timers, then abort these steps.
         if (!window->m_timers.contains(id))
             return;
@@ -253,10 +257,12 @@ i32 Window::run_timer_initialization_steps(Bindings::TimerHandler handler, i32 t
     // 11. FIXME: Set task's timer nesting level to nesting level.
 
     // 12. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.
-    auto completion_step = [window = NonnullRefPtr(*this), task = move(task)]() mutable {
-        HTML::queue_global_task(HTML::Task::Source::TimerTask, *window->wrapper(), [task = move(task)]() mutable {
-            task();
-        });
+    auto completion_step = [weak_window = make_weak_ptr(), task = move(task)]() mutable {
+        auto window = weak_window.strong_ref();
+        if (!window)
+            return;
+
+        HTML::queue_global_task(HTML::Task::Source::TimerTask, *window->wrapper(), move(task));
     };
 
     // 13. Run steps after a timeout given global, "setTimeout/setInterval", timeout, completionStep, and id.

+ 2 - 0
Userland/Libraries/LibWeb/HTML/Window.h

@@ -10,6 +10,7 @@
 #include <AK/IDAllocator.h>
 #include <AK/RefCounted.h>
 #include <AK/RefPtr.h>
+#include <AK/Weakable.h>
 #include <LibWeb/Bindings/WindowObject.h>
 #include <LibWeb/Bindings/Wrappable.h>
 #include <LibWeb/CSS/MediaQueryList.h>
@@ -26,6 +27,7 @@ class RequestAnimationFrameCallback;
 
 class Window final
     : public RefCounted<Window>
+    , public Weakable<Window>
     , public DOM::EventTarget
     , public HTML::GlobalEventHandlers {
 public: