Title: [175107] branches/safari-600.3-branch/Source/WebCore

Diff

Modified: branches/safari-600.3-branch/Source/WebCore/ChangeLog (175106 => 175107)


--- branches/safari-600.3-branch/Source/WebCore/ChangeLog	2014-10-23 09:23:38 UTC (rev 175106)
+++ branches/safari-600.3-branch/Source/WebCore/ChangeLog	2014-10-23 09:24:51 UTC (rev 175107)
@@ -1,3 +1,55 @@
+2014-10-23  Babak Shafiei  <[email protected]>
+
+        Merge r172963.
+
+    2014-08-25  Gavin Barraclough  <[email protected]>
+
+            DOMTimer may be deleted during timer fire
+            https://bugs.webkit.org/show_bug.cgi?id=136198
+
+            Reviewed by Geoff Garen.
+
+            Consequentially ScheduledActions may also be deleted mid execution.
+            This is fairly surprising & fragile, let's make this simpler.
+
+            Currently DOMTimer instances are effectively owned by the ScriptExecutionContext.
+            There is a 1-1 mapping between timers and contexts, all timers are help in a map
+            on the context and if the context goes away all timers are deleted. Rather than
+            being implemented in a straightforward fashion (a smart pointer type for the map
+            value) this is currently implemented by having the timer objects listen for the
+            context going away using contextDestroyed, and deleting themselves if so.
+
+            Switch to using a smart pointer for values of m_timeouts in ScriptExecutionContext.
+            By using a RefCounted object we can also extend the lifetime of the DOMTimer instance
+            from within the DOMTimer::fired method, so the object is not destroyed while the
+            member function is still on the stack.
+
+            * WebCore.xcodeproj/project.pbxproj:
+                - project -> private since DOMTimer could no longer be a forward declare in ScriptExecutionContext.h.
+            * dom/ScriptExecutionContext.cpp:
+            (WebCore::ScriptExecutionContext::adjustMinimumTimerInterval):
+            (WebCore::ScriptExecutionContext::didChangeTimerAlignmentInterval):
+                - auto* -> auto& since value type in map is no longer a raw pointer.
+            * dom/ScriptExecutionContext.h:
+            (WebCore::ScriptExecutionContext::addTimeout):
+                - DOMTimer* -> PassRefPtr<DOMTimer>
+            * page/DOMTimer.cpp:
+            (WebCore::DOMTimer::DOMTimer):
+                - adopt the initial ref, and pass to addTimeout.
+            (WebCore::DOMTimer::install):
+                - updated comment.
+            (WebCore::DOMTimer::removeById):
+                - instead of explicitly deleting the timer and assuming this will implicitly remove it from the context map,
+                  we explicitly remove it from the context map and assume this will implicitly deleting the timer!
+            (WebCore::DOMTimer::fired):
+                - Add a RefPtr to keep the DOMTimer object alive until the fired method completes; to cancel a one-shot timer
+                  just remove it from the context's map, rather than explicitly deleting it.
+            (WebCore::DOMTimer::~DOMTimer): Deleted.
+            (WebCore::DOMTimer::contextDestroyed): Deleted.
+                - no need! object lifetime management now handled by smart pointers.
+            * page/DOMTimer.h:
+                - added parent class RefCounted<DOMTimer>.
+
 2014-10-21  Dana Burkart  <[email protected]>
 
         Merge r174703

Modified: branches/safari-600.3-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj (175106 => 175107)


--- branches/safari-600.3-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2014-10-23 09:23:38 UTC (rev 175106)
+++ branches/safari-600.3-branch/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2014-10-23 09:24:51 UTC (rev 175107)
@@ -646,7 +646,7 @@
 		185BCF280F3279CE000EA262 /* ThreadTimers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 185BCF260F3279CE000EA262 /* ThreadTimers.cpp */; };
 		185BCF290F3279CE000EA262 /* ThreadTimers.h in Headers */ = {isa = PBXBuildFile; fileRef = 185BCF270F3279CE000EA262 /* ThreadTimers.h */; };
 		188604B30F2E654A000B6443 /* DOMTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 188604B10F2E654A000B6443 /* DOMTimer.cpp */; };
-		188604B40F2E654A000B6443 /* DOMTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 188604B20F2E654A000B6443 /* DOMTimer.h */; };
+		188604B40F2E654A000B6443 /* DOMTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 188604B20F2E654A000B6443 /* DOMTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		18F831B80FD48C7800D8C56B /* WorkerLoaderProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 18F831B70FD48C7800D8C56B /* WorkerLoaderProxy.h */; };
 		1921327411C0E6BB00456238 /* SVGFEConvolveMatrixElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1921327111C0E6BB00456238 /* SVGFEConvolveMatrixElement.cpp */; };
 		1921327511C0E6BB00456238 /* SVGFEConvolveMatrixElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 1921327211C0E6BB00456238 /* SVGFEConvolveMatrixElement.h */; };
@@ -2119,7 +2119,7 @@
 		5DB1BC6B10715A6400EFAA49 /* TransformSourceLibxslt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5DB1BC6910715A6400EFAA49 /* TransformSourceLibxslt.cpp */; };
 		5DF7F5C20F01F92A00526B4B /* CSSPropertyNames.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 656580EF09D12B20000E61D7 /* CSSPropertyNames.h */; };
 		5DFE8F560D16477B0076E937 /* ScheduledAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCA378BA0D15F64200B793D6 /* ScheduledAction.cpp */; };
-		5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA378BB0D15F64200B793D6 /* ScheduledAction.h */; };
+		5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA378BB0D15F64200B793D6 /* ScheduledAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		5DFEBAB718592B6D00C75BEB /* WebKitAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFEBAB618592B6D00C75BEB /* WebKitAvailability.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		5F2DBBE9178E3C8100141486 /* CertificateInfoMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5F2DBBE7178E332D00141486 /* CertificateInfoMac.mm */; };
 		5FA904CA178E61F5004C8A2D /* CertificateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F2DBBE8178E336900141486 /* CertificateInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2130,7 +2130,7 @@
 		628D214C12131ED10055DCFC /* NetworkingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 628D214B12131ED10055DCFC /* NetworkingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		628D214E12131EF40055DCFC /* FrameNetworkingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 628D214D12131EF40055DCFC /* FrameNetworkingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		62C1217C11AB9E77003C462C /* SuspendableTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62C1217A11AB9E76003C462C /* SuspendableTimer.cpp */; };
-		62C1217D11AB9E77003C462C /* SuspendableTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 62C1217B11AB9E77003C462C /* SuspendableTimer.h */; };
+		62C1217D11AB9E77003C462C /* SuspendableTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 62C1217B11AB9E77003C462C /* SuspendableTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		62CD32591157E57C0063B0A7 /* CustomEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62CD32561157E57C0063B0A7 /* CustomEvent.cpp */; };
 		62CD325A1157E57C0063B0A7 /* CustomEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 62CD32571157E57C0063B0A7 /* CustomEvent.h */; };
 		63189AE30E83A33300012E41 /* NodeRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 63189AE20E83A33300012E41 /* NodeRareData.h */; settings = {ATTRIBUTES = (); }; };

Modified: branches/safari-600.3-branch/Source/WebCore/dom/ScriptExecutionContext.cpp (175106 => 175107)


--- branches/safari-600.3-branch/Source/WebCore/dom/ScriptExecutionContext.cpp	2014-10-23 09:23:38 UTC (rev 175106)
+++ branches/safari-600.3-branch/Source/WebCore/dom/ScriptExecutionContext.cpp	2014-10-23 09:24:51 UTC (rev 175107)
@@ -416,7 +416,7 @@
 void ScriptExecutionContext::adjustMinimumTimerInterval(double oldMinimumTimerInterval)
 {
     if (minimumTimerInterval() != oldMinimumTimerInterval) {
-        for (auto* timer : m_timeouts.values())
+        for (auto& timer : m_timeouts.values())
             timer->adjustMinimumTimerInterval(oldMinimumTimerInterval);
     }
 }
@@ -433,7 +433,7 @@
 
 void ScriptExecutionContext::didChangeTimerAlignmentInterval()
 {
-    for (auto* timer : m_timeouts.values())
+    for (auto& timer : m_timeouts.values())
         timer->didChangeAlignmentInterval();
 }
 

Modified: branches/safari-600.3-branch/Source/WebCore/dom/ScriptExecutionContext.h (175106 => 175107)


--- branches/safari-600.3-branch/Source/WebCore/dom/ScriptExecutionContext.h	2014-10-23 09:23:38 UTC (rev 175106)
+++ branches/safari-600.3-branch/Source/WebCore/dom/ScriptExecutionContext.h	2014-10-23 09:24:51 UTC (rev 175107)
@@ -29,6 +29,8 @@
 #define ScriptExecutionContext_h
 
 #include "ActiveDOMObject.h"
+#include "DOMTimer.h"
+#include "ScheduledAction.h"
 #include "SecurityContext.h"
 #include "Supplementable.h"
 #include <runtime/ConsoleTypes.h>
@@ -47,7 +49,6 @@
 
 class CachedScript;
 class DatabaseContext;
-class DOMTimer;
 class EventQueue;
 class EventTarget;
 class MessagePort;
@@ -150,7 +151,7 @@
     // Gets the next id in a circular sequence from 1 to 2^31-1.
     int circularSequentialID();
 
-    bool addTimeout(int timeoutId, DOMTimer* timer) { return m_timeouts.add(timeoutId, timer).isNewEntry; }
+    bool addTimeout(int timeoutId, PassRefPtr<DOMTimer> timer) { return m_timeouts.add(timeoutId, timer).isNewEntry; }
     void removeTimeout(int timeoutId) { m_timeouts.remove(timeoutId); }
     DOMTimer* findTimeout(int timeoutId) { return m_timeouts.get(timeoutId); }
 
@@ -205,7 +206,7 @@
     HashSet<ActiveDOMObject*> m_activeDOMObjects;
 
     int m_circularSequentialID;
-    HashMap<int, DOMTimer*> m_timeouts;
+    HashMap<int, RefPtr<DOMTimer>> m_timeouts;
 
     bool m_inDispatchErrorEvent;
     class PendingException;

Modified: branches/safari-600.3-branch/Source/WebCore/page/DOMTimer.cpp (175106 => 175107)


--- branches/safari-600.3-branch/Source/WebCore/page/DOMTimer.cpp	2014-10-23 09:23:38 UTC (rev 175106)
+++ branches/safari-600.3-branch/Source/WebCore/page/DOMTimer.cpp	2014-10-23 09:24:51 UTC (rev 175107)
@@ -65,10 +65,12 @@
     , m_originalInterval(interval)
     , m_shouldForwardUserGesture(shouldForwardUserGesture(interval, m_nestingLevel))
 {
+    RefPtr<DOMTimer> reference = adoptRef(this);
+
     // Keep asking for the next id until we're given one that we don't already have.
     do {
         m_timeoutId = context->circularSequentialID();
-    } while (!context->addTimeout(m_timeoutId, this));
+    } while (!context->addTimeout(m_timeoutId, reference));
 
     double intervalMilliseconds = intervalClampedToMinimum(interval, context->minimumTimerInterval());
     if (singleShot)
@@ -77,17 +79,11 @@
         startRepeating(intervalMilliseconds);
 }
 
-DOMTimer::~DOMTimer()
-{
-    if (scriptExecutionContext())
-        scriptExecutionContext()->removeTimeout(m_timeoutId);
-}
-
 int DOMTimer::install(ScriptExecutionContext* context, std::unique_ptr<ScheduledAction> action, int timeout, bool singleShot)
 {
-    // DOMTimer constructor links the new timer into a list of ActiveDOMObjects held by the 'context'.
-    // The timer is deleted when context is deleted (DOMTimer::contextDestroyed) or explicitly via DOMTimer::removeById(),
-    // or if it is a one-time timer and it has fired (DOMTimer::fired).
+    // DOMTimer constructor passes ownership of the initial ref on the object to the constructor.
+    // This reference will be released automatically when a one-shot timer fires, when the context
+    // is destroyed, or if explicitly cancelled by removeById. 
     DOMTimer* timer = new DOMTimer(context, WTF::move(action), timeout, singleShot);
 #if PLATFORM(IOS)
     if (context->isDocument()) {
@@ -115,12 +111,16 @@
         return;
 
     InspectorInstrumentation::didRemoveTimer(context, timeoutId);
-
-    delete context->findTimeout(timeoutId);
+    context->removeTimeout(timeoutId);
 }
 
 void DOMTimer::fired()
 {
+    // Retain this - if the timer is cancelled while this function is on the stack (implicitly and always
+    // for one-shot timers, or if removeById is called on itself from within an interval timer fire) then
+    // wait unit the end of this function to delete DOMTimer.
+    RefPtr<DOMTimer> reference = this;
+
     ScriptExecutionContext* context = scriptExecutionContext();
     ASSERT(context);
 #if PLATFORM(IOS)
@@ -148,7 +148,6 @@
                 augmentRepeatInterval(minimumInterval - repeatInterval());
         }
 
-        // No access to member variables after this point, it can delete the timer.
         m_action->execute(context);
 
         InspectorInstrumentation::didFireTimer(cookie);
@@ -156,12 +155,8 @@
         return;
     }
 
-    // Delete timer before executing the action for one-shot timers.
-    std::unique_ptr<ScheduledAction> action = ""
+    context->removeTimeout(m_timeoutId);
 
-    // No access to member variables after this point.
-    delete this;
-
 #if PLATFORM(IOS)
     bool shouldReportLackOfChanges;
     bool shouldBeginObservingChanges;
@@ -179,7 +174,7 @@
     }
 #endif
 
-    action->execute(context);
+    m_action->execute(context);
 
 #if PLATFORM(IOS)
     if (shouldBeginObservingChanges) {
@@ -196,12 +191,6 @@
     timerNestingLevel = 0;
 }
 
-void DOMTimer::contextDestroyed()
-{
-    SuspendableTimer::contextDestroyed();
-    delete this;
-}
-
 void DOMTimer::didStop()
 {
     // Need to release JS objects potentially protected by ScheduledAction

Modified: branches/safari-600.3-branch/Source/WebCore/page/DOMTimer.h (175106 => 175107)


--- branches/safari-600.3-branch/Source/WebCore/page/DOMTimer.h	2014-10-23 09:23:38 UTC (rev 175106)
+++ branches/safari-600.3-branch/Source/WebCore/page/DOMTimer.h	2014-10-23 09:24:51 UTC (rev 175107)
@@ -28,15 +28,17 @@
 #define DOMTimer_h
 
 #include "SuspendableTimer.h"
+#include <WTF/RefCounted.h>
 #include <memory>
 
 namespace WebCore {
 
     class ScheduledAction;
 
-    class DOMTimer final : public SuspendableTimer {
+    class DOMTimer final : public RefCounted<DOMTimer>, public SuspendableTimer {
+        WTF_MAKE_NONCOPYABLE(DOMTimer);
+        WTF_MAKE_FAST_ALLOCATED;
     public:
-        virtual ~DOMTimer();
         // Creates a new timer owned by specified ScriptExecutionContext, starts it
         // and returns its Id.
         static int install(ScriptExecutionContext*, std::unique_ptr<ScheduledAction>, int timeout, bool singleShot);
@@ -49,17 +51,11 @@
 
     private:
         DOMTimer(ScriptExecutionContext*, std::unique_ptr<ScheduledAction>, int interval, bool singleShot);
-        virtual void fired() override;
+        double intervalClampedToMinimum(int timeout, double minimumTimerInterval) const;
 
-        // ActiveDOMObject
-        virtual void contextDestroyed() override;
-
         // SuspendableTimer
+        virtual void fired() override;
         virtual void didStop() override;
-
-        double intervalClampedToMinimum(int timeout, double minimumTimerInterval) const;
-
-        // Retuns timer fire time rounded to the next multiple of timer alignment interval.
         virtual double alignedFireTime(double) const override;
 
         int m_timeoutId;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to