<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[172963] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/172963">172963</a></dd>
<dt>Author</dt> <dd>barraclough@apple.com</dd>
<dt>Date</dt> <dd>2014-08-26 10:58:11 -0700 (Tue, 26 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>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 &amp; 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 -&gt; private since DOMTimer could no longer be a forward declare in ScriptExecutionContext.h.
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::adjustMinimumTimerInterval):
(WebCore::ScriptExecutionContext::didChangeTimerAlignmentInterval):
    - auto* -&gt; auto&amp; since value type in map is no longer a raw pointer.
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::addTimeout):
    - DOMTimer* -&gt; PassRefPtr&lt;DOMTimer&gt;
* 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&lt;DOMTimer&gt;.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoredomScriptExecutionContextcpp">trunk/Source/WebCore/dom/ScriptExecutionContext.cpp</a></li>
<li><a href="#trunkSourceWebCoredomScriptExecutionContexth">trunk/Source/WebCore/dom/ScriptExecutionContext.h</a></li>
<li><a href="#trunkSourceWebCorepageDOMTimercpp">trunk/Source/WebCore/page/DOMTimer.cpp</a></li>
<li><a href="#trunkSourceWebCorepageDOMTimerh">trunk/Source/WebCore/page/DOMTimer.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (172962 => 172963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-08-26 17:34:21 UTC (rev 172962)
+++ trunk/Source/WebCore/ChangeLog        2014-08-26 17:58:11 UTC (rev 172963)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2014-08-25  Gavin Barraclough  &lt;barraclough@apple.com&gt;
+
+        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 &amp; 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 -&gt; private since DOMTimer could no longer be a forward declare in ScriptExecutionContext.h.
+        * dom/ScriptExecutionContext.cpp:
+        (WebCore::ScriptExecutionContext::adjustMinimumTimerInterval):
+        (WebCore::ScriptExecutionContext::didChangeTimerAlignmentInterval):
+            - auto* -&gt; auto&amp; since value type in map is no longer a raw pointer.
+        * dom/ScriptExecutionContext.h:
+        (WebCore::ScriptExecutionContext::addTimeout):
+            - DOMTimer* -&gt; PassRefPtr&lt;DOMTimer&gt;
+        * 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&lt;DOMTimer&gt;.
+
</ins><span class="cx"> 2014-08-26  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Selection background is rendered white when unfocused with recent GTK+
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (172962 => 172963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-08-26 17:34:21 UTC (rev 172962)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-08-26 17:58:11 UTC (rev 172963)
</span><span class="lines">@@ -647,7 +647,7 @@
</span><span class="cx">                 185BCF280F3279CE000EA262 /* ThreadTimers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 185BCF260F3279CE000EA262 /* ThreadTimers.cpp */; };
</span><span class="cx">                 185BCF290F3279CE000EA262 /* ThreadTimers.h in Headers */ = {isa = PBXBuildFile; fileRef = 185BCF270F3279CE000EA262 /* ThreadTimers.h */; };
</span><span class="cx">                 188604B30F2E654A000B6443 /* DOMTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 188604B10F2E654A000B6443 /* DOMTimer.cpp */; };
</span><del>-                188604B40F2E654A000B6443 /* DOMTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 188604B20F2E654A000B6443 /* DOMTimer.h */; };
</del><ins>+                188604B40F2E654A000B6443 /* DOMTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 188604B20F2E654A000B6443 /* DOMTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 18F831B80FD48C7800D8C56B /* WorkerLoaderProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 18F831B70FD48C7800D8C56B /* WorkerLoaderProxy.h */; };
</span><span class="cx">                 1921327411C0E6BB00456238 /* SVGFEConvolveMatrixElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1921327111C0E6BB00456238 /* SVGFEConvolveMatrixElement.cpp */; };
</span><span class="cx">                 1921327511C0E6BB00456238 /* SVGFEConvolveMatrixElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 1921327211C0E6BB00456238 /* SVGFEConvolveMatrixElement.h */; };
</span><span class="lines">@@ -2111,7 +2111,7 @@
</span><span class="cx">                 5DB1BC6B10715A6400EFAA49 /* TransformSourceLibxslt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5DB1BC6910715A6400EFAA49 /* TransformSourceLibxslt.cpp */; };
</span><span class="cx">                 5DF7F5C20F01F92A00526B4B /* CSSPropertyNames.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 656580EF09D12B20000E61D7 /* CSSPropertyNames.h */; };
</span><span class="cx">                 5DFE8F560D16477B0076E937 /* ScheduledAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCA378BA0D15F64200B793D6 /* ScheduledAction.cpp */; };
</span><del>-                5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA378BB0D15F64200B793D6 /* ScheduledAction.h */; };
</del><ins>+                5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA378BB0D15F64200B793D6 /* ScheduledAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 5DFEBAB718592B6D00C75BEB /* WebKitAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFEBAB618592B6D00C75BEB /* WebKitAvailability.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 5F2DBBE9178E3C8100141486 /* CertificateInfoMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5F2DBBE7178E332D00141486 /* CertificateInfoMac.mm */; };
</span><span class="cx">                 5FA904CA178E61F5004C8A2D /* CertificateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F2DBBE8178E336900141486 /* CertificateInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -2122,7 +2122,7 @@
</span><span class="cx">                 628D214C12131ED10055DCFC /* NetworkingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 628D214B12131ED10055DCFC /* NetworkingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 628D214E12131EF40055DCFC /* FrameNetworkingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 628D214D12131EF40055DCFC /* FrameNetworkingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 62C1217C11AB9E77003C462C /* SuspendableTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62C1217A11AB9E76003C462C /* SuspendableTimer.cpp */; };
</span><del>-                62C1217D11AB9E77003C462C /* SuspendableTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 62C1217B11AB9E77003C462C /* SuspendableTimer.h */; };
</del><ins>+                62C1217D11AB9E77003C462C /* SuspendableTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 62C1217B11AB9E77003C462C /* SuspendableTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 62CD32591157E57C0063B0A7 /* CustomEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62CD32561157E57C0063B0A7 /* CustomEvent.cpp */; };
</span><span class="cx">                 62CD325A1157E57C0063B0A7 /* CustomEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 62CD32571157E57C0063B0A7 /* CustomEvent.h */; };
</span><span class="cx">                 63189AE30E83A33300012E41 /* NodeRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 63189AE20E83A33300012E41 /* NodeRareData.h */; settings = {ATTRIBUTES = (); }; };
</span></span></pre></div>
<a id="trunkSourceWebCoredomScriptExecutionContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ScriptExecutionContext.cpp (172962 => 172963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ScriptExecutionContext.cpp        2014-08-26 17:34:21 UTC (rev 172962)
+++ trunk/Source/WebCore/dom/ScriptExecutionContext.cpp        2014-08-26 17:58:11 UTC (rev 172963)
</span><span class="lines">@@ -416,7 +416,7 @@
</span><span class="cx"> void ScriptExecutionContext::adjustMinimumTimerInterval(double oldMinimumTimerInterval)
</span><span class="cx"> {
</span><span class="cx">     if (minimumTimerInterval() != oldMinimumTimerInterval) {
</span><del>-        for (auto* timer : m_timeouts.values())
</del><ins>+        for (auto&amp; timer : m_timeouts.values())
</ins><span class="cx">             timer-&gt;adjustMinimumTimerInterval(oldMinimumTimerInterval);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -433,7 +433,7 @@
</span><span class="cx"> 
</span><span class="cx"> void ScriptExecutionContext::didChangeTimerAlignmentInterval()
</span><span class="cx"> {
</span><del>-    for (auto* timer : m_timeouts.values())
</del><ins>+    for (auto&amp; timer : m_timeouts.values())
</ins><span class="cx">         timer-&gt;didChangeAlignmentInterval();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomScriptExecutionContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ScriptExecutionContext.h (172962 => 172963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ScriptExecutionContext.h        2014-08-26 17:34:21 UTC (rev 172962)
+++ trunk/Source/WebCore/dom/ScriptExecutionContext.h        2014-08-26 17:58:11 UTC (rev 172963)
</span><span class="lines">@@ -29,6 +29,8 @@
</span><span class="cx"> #define ScriptExecutionContext_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ActiveDOMObject.h&quot;
</span><ins>+#include &quot;DOMTimer.h&quot;
+#include &quot;ScheduledAction.h&quot;
</ins><span class="cx"> #include &quot;SecurityContext.h&quot;
</span><span class="cx"> #include &quot;Supplementable.h&quot;
</span><span class="cx"> #include &lt;runtime/ConsoleTypes.h&gt;
</span><span class="lines">@@ -47,7 +49,6 @@
</span><span class="cx"> 
</span><span class="cx"> class CachedScript;
</span><span class="cx"> class DatabaseContext;
</span><del>-class DOMTimer;
</del><span class="cx"> class EventQueue;
</span><span class="cx"> class EventTarget;
</span><span class="cx"> class MessagePort;
</span><span class="lines">@@ -150,7 +151,7 @@
</span><span class="cx">     // Gets the next id in a circular sequence from 1 to 2^31-1.
</span><span class="cx">     int circularSequentialID();
</span><span class="cx"> 
</span><del>-    bool addTimeout(int timeoutId, DOMTimer* timer) { return m_timeouts.add(timeoutId, timer).isNewEntry; }
</del><ins>+    bool addTimeout(int timeoutId, PassRefPtr&lt;DOMTimer&gt; timer) { return m_timeouts.add(timeoutId, timer).isNewEntry; }
</ins><span class="cx">     void removeTimeout(int timeoutId) { m_timeouts.remove(timeoutId); }
</span><span class="cx">     DOMTimer* findTimeout(int timeoutId) { return m_timeouts.get(timeoutId); }
</span><span class="cx"> 
</span><span class="lines">@@ -205,7 +206,7 @@
</span><span class="cx">     HashSet&lt;ActiveDOMObject*&gt; m_activeDOMObjects;
</span><span class="cx"> 
</span><span class="cx">     int m_circularSequentialID;
</span><del>-    HashMap&lt;int, DOMTimer*&gt; m_timeouts;
</del><ins>+    HashMap&lt;int, RefPtr&lt;DOMTimer&gt;&gt; m_timeouts;
</ins><span class="cx"> 
</span><span class="cx">     bool m_inDispatchErrorEvent;
</span><span class="cx">     class PendingException;
</span></span></pre></div>
<a id="trunkSourceWebCorepageDOMTimercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DOMTimer.cpp (172962 => 172963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DOMTimer.cpp        2014-08-26 17:34:21 UTC (rev 172962)
+++ trunk/Source/WebCore/page/DOMTimer.cpp        2014-08-26 17:58:11 UTC (rev 172963)
</span><span class="lines">@@ -65,10 +65,12 @@
</span><span class="cx">     , m_originalInterval(interval)
</span><span class="cx">     , m_shouldForwardUserGesture(shouldForwardUserGesture(interval, m_nestingLevel))
</span><span class="cx"> {
</span><ins>+    RefPtr&lt;DOMTimer&gt; reference = adoptRef(this);
+
</ins><span class="cx">     // Keep asking for the next id until we're given one that we don't already have.
</span><span class="cx">     do {
</span><span class="cx">         m_timeoutId = context-&gt;circularSequentialID();
</span><del>-    } while (!context-&gt;addTimeout(m_timeoutId, this));
</del><ins>+    } while (!context-&gt;addTimeout(m_timeoutId, reference));
</ins><span class="cx"> 
</span><span class="cx">     double intervalMilliseconds = intervalClampedToMinimum(interval, context-&gt;minimumTimerInterval());
</span><span class="cx">     if (singleShot)
</span><span class="lines">@@ -77,17 +79,11 @@
</span><span class="cx">         startRepeating(intervalMilliseconds);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-DOMTimer::~DOMTimer()
-{
-    if (scriptExecutionContext())
-        scriptExecutionContext()-&gt;removeTimeout(m_timeoutId);
-}
-
</del><span class="cx"> int DOMTimer::install(ScriptExecutionContext* context, std::unique_ptr&lt;ScheduledAction&gt; action, int timeout, bool singleShot)
</span><span class="cx"> {
</span><del>-    // 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).
</del><ins>+    // 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. 
</ins><span class="cx">     DOMTimer* timer = new DOMTimer(context, WTF::move(action), timeout, singleShot);
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     if (context-&gt;isDocument()) {
</span><span class="lines">@@ -115,12 +111,16 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     InspectorInstrumentation::didRemoveTimer(context, timeoutId);
</span><del>-
-    delete context-&gt;findTimeout(timeoutId);
</del><ins>+    context-&gt;removeTimeout(timeoutId);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void DOMTimer::fired()
</span><span class="cx"> {
</span><ins>+    // 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&lt;DOMTimer&gt; reference = this;
+
</ins><span class="cx">     ScriptExecutionContext* context = scriptExecutionContext();
</span><span class="cx">     ASSERT(context);
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="lines">@@ -148,7 +148,6 @@
</span><span class="cx">                 augmentRepeatInterval(minimumInterval - repeatInterval());
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // No access to member variables after this point, it can delete the timer.
</del><span class="cx">         m_action-&gt;execute(context);
</span><span class="cx"> 
</span><span class="cx">         InspectorInstrumentation::didFireTimer(cookie);
</span><span class="lines">@@ -156,12 +155,8 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Delete timer before executing the action for one-shot timers.
-    std::unique_ptr&lt;ScheduledAction&gt; action = WTF::move(m_action);
</del><ins>+    context-&gt;removeTimeout(m_timeoutId);
</ins><span class="cx"> 
</span><del>-    // No access to member variables after this point.
-    delete this;
-
</del><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     bool shouldReportLackOfChanges;
</span><span class="cx">     bool shouldBeginObservingChanges;
</span><span class="lines">@@ -179,7 +174,7 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    action-&gt;execute(context);
</del><ins>+    m_action-&gt;execute(context);
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     if (shouldBeginObservingChanges) {
</span><span class="lines">@@ -196,12 +191,6 @@
</span><span class="cx">     timerNestingLevel = 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void DOMTimer::contextDestroyed()
-{
-    SuspendableTimer::contextDestroyed();
-    delete this;
-}
-
</del><span class="cx"> void DOMTimer::didStop()
</span><span class="cx"> {
</span><span class="cx">     // Need to release JS objects potentially protected by ScheduledAction
</span></span></pre></div>
<a id="trunkSourceWebCorepageDOMTimerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DOMTimer.h (172962 => 172963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DOMTimer.h        2014-08-26 17:34:21 UTC (rev 172962)
+++ trunk/Source/WebCore/page/DOMTimer.h        2014-08-26 17:58:11 UTC (rev 172963)
</span><span class="lines">@@ -28,15 +28,17 @@
</span><span class="cx"> #define DOMTimer_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;SuspendableTimer.h&quot;
</span><ins>+#include &lt;WTF/RefCounted.h&gt;
</ins><span class="cx"> #include &lt;memory&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx">     class ScheduledAction;
</span><span class="cx"> 
</span><del>-    class DOMTimer final : public SuspendableTimer {
</del><ins>+    class DOMTimer final : public RefCounted&lt;DOMTimer&gt;, public SuspendableTimer {
+        WTF_MAKE_NONCOPYABLE(DOMTimer);
+        WTF_MAKE_FAST_ALLOCATED;
</ins><span class="cx">     public:
</span><del>-        virtual ~DOMTimer();
</del><span class="cx">         // Creates a new timer owned by specified ScriptExecutionContext, starts it
</span><span class="cx">         // and returns its Id.
</span><span class="cx">         static int install(ScriptExecutionContext*, std::unique_ptr&lt;ScheduledAction&gt;, int timeout, bool singleShot);
</span><span class="lines">@@ -49,17 +51,11 @@
</span><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         DOMTimer(ScriptExecutionContext*, std::unique_ptr&lt;ScheduledAction&gt;, int interval, bool singleShot);
</span><del>-        virtual void fired() override;
</del><ins>+        double intervalClampedToMinimum(int timeout, double minimumTimerInterval) const;
</ins><span class="cx"> 
</span><del>-        // ActiveDOMObject
-        virtual void contextDestroyed() override;
-
</del><span class="cx">         // SuspendableTimer
</span><ins>+        virtual void fired() override;
</ins><span class="cx">         virtual void didStop() override;
</span><del>-
-        double intervalClampedToMinimum(int timeout, double minimumTimerInterval) const;
-
-        // Retuns timer fire time rounded to the next multiple of timer alignment interval.
</del><span class="cx">         virtual double alignedFireTime(double) const override;
</span><span class="cx"> 
</span><span class="cx">         int m_timeoutId;
</span></span></pre>
</div>
</div>

</body>
</html>