Bug 851781 - Make sure that we don't reenter scriptblocker removal when we don't expect to. r=smaug, a=lsblakk
authorBoris Zbarsky <bzbarsky@mit.edu>
Sat, 30 Mar 2013 00:13:52 -0400
changeset 118998 72ec41538d37662052873673a56c6dc27f5a9f0e
parent 118997 0c6effe4d05f3f60f7bfbc3ad1a67957c08088b0
child 118999 6deb867802b9636608529404a86968423c929c2c
push id642
push userryanvm@gmail.com
push dateTue, 09 Apr 2013 13:46:51 +0000
reviewerssmaug, lsblakk
bugs851781
milestone18.0
Bug 851781 - Make sure that we don't reenter scriptblocker removal when we don't expect to. r=smaug, a=lsblakk
content/base/src/nsContentUtils.cpp
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4991,43 +4991,57 @@ nsContentUtils::AddScriptBlocker()
   if (!sScriptBlockerCount) {
     NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
                  "Should not already have a count");
     sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Length();
   }
   ++sScriptBlockerCount;
 }
 
+#ifdef DEBUG
+static bool sRemovingScriptBlockers = false;
+#endif
+
 /* static */
 void
 nsContentUtils::RemoveScriptBlocker()
 {
+  MOZ_ASSERT(!sRemovingScriptBlockers);
   NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers");
   --sScriptBlockerCount;
   if (sScriptBlockerCount) {
     return;
   }
 
   uint32_t firstBlocker = sRunnersCountAtFirstBlocker;
   uint32_t lastBlocker = sBlockedScriptRunners->Length();
   uint32_t originalFirstBlocker = firstBlocker;
   uint32_t blockersCount = lastBlocker - firstBlocker;
   sRunnersCountAtFirstBlocker = 0;
   NS_ASSERTION(firstBlocker <= lastBlocker,
                "bad sRunnersCountAtFirstBlocker");
 
   while (firstBlocker < lastBlocker) {
-    nsCOMPtr<nsIRunnable> runnable = (*sBlockedScriptRunners)[firstBlocker];
+    nsCOMPtr<nsIRunnable> runnable;
+    runnable.swap((*sBlockedScriptRunners)[firstBlocker]);
     ++firstBlocker;
 
+    // Calling the runnable can reenter us
     runnable->Run();
+    // So can dropping the reference to the runnable
+    runnable = nullptr;
+
     NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
                  "Bad count");
     NS_ASSERTION(!sScriptBlockerCount, "This is really bad");
   }
+#ifdef DEBUG
+  AutoRestore<bool> removingScriptBlockers(sRemovingScriptBlockers);
+  sRemovingScriptBlockers = true;
+#endif
   sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount);
 }
 
 /* static */
 bool
 nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable)
 {
   if (!aRunnable) {