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;