diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -9118,16 +9118,43 @@ nsCSSFrameConstructor::ReinsertContent(n
     // If ContentRemoved just reconstructed everything, there is no need to
     // reinsert the content here
     res = ContentInserted(aContainer, aChild, ix, nsnull);
   }
 
   return res;
 }
 
+static void
+DoDeletingFrameSubtree(nsFrameManager* aFrameManager,
+                       nsVoidArray&    aDestroyQueue,
+                       nsIFrame*       aRemovedFrame,
+                       nsIFrame*       aFrame);
+
+static void
+DoDeletingOverflowContainers(nsFrameManager* aFrameManager,
+                             nsVoidArray&    aDestroyQueue,
+                             nsIFrame*       aRemovedFrame,
+                             nsIFrame*       aFrame)
+{
+  // The invariant that "continuing frames should be found as part of the
+  // walk over the top-most frame's continuing frames" does not hold for
+  // out-of-flow overflow containers, so we need to walk them too.
+  // Note that DoDeletingFrameSubtree() skips the child lists where
+  // overflow containers live so we won't process them twice.
+  const PRBool orphanSubtree = aRemovedFrame == aFrame;
+  for (nsIFrame* next = aFrame->GetNextContinuation();
+       next && (next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
+       next = next->GetNextContinuation()) {
+    DoDeletingFrameSubtree(aFrameManager, aDestroyQueue,
+                           orphanSubtree ? next : aRemovedFrame,
+                           next);
+  }
+}
+
 /**
  * Called when a frame subtree is about to be deleted. Two important
  * things happen:
  *
  * 1. For each frame in the subtree, we remove the mapping from the
  *    content object to its frame
  *
  * 2. For child frames that have been moved out of the flow, we enqueue
@@ -9141,40 +9168,45 @@ nsCSSFrameConstructor::ReinsertContent(n
  * @param   aRemovedFrame this is the frame that was removed from the
  *            content model. As we recurse we need to remember this so we
  *            can check if out-of-flow frames are a descendant of the frame
  *            being removed
  * @param   aFrame the local subtree that is being deleted. This is initially
  *            the same as aRemovedFrame, but as we recurse down the tree
  *            this changes
  */
-static nsresult
+static void
 DoDeletingFrameSubtree(nsFrameManager* aFrameManager,
                        nsVoidArray&    aDestroyQueue,
                        nsIFrame*       aRemovedFrame,
                        nsIFrame*       aFrame)
 {
+#undef RECURSE
+#define RECURSE(top, child)                                                  \
+  DoDeletingFrameSubtree(aFrameManager, aDestroyQueue, (top), (child));      \
+  DoDeletingOverflowContainers(aFrameManager, aDestroyQueue, (top), (child));
+
   // Remove the mapping from the content object to its frame.
   nsIContent* content = aFrame->GetContent();
   if (content) {
     aFrameManager->RemoveAsPrimaryFrame(content, aFrame);
     aFrameManager->ClearAllUndisplayedContentIn(content);
   }
 
   nsIAtom* childListName = nsnull;
   PRInt32 childListIndex = 0;
 
   do {
     // Walk aFrame's normal flow child frames looking for placeholder frames.
     nsIFrame* childFrame = aFrame->GetFirstChild(childListName);
     for (; childFrame; childFrame = childFrame->GetNextSibling()) {
+      NS_ASSERTION(!(childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
+                   "out-of-flow on wrong child list");
       if (NS_LIKELY(nsGkAtoms::placeholderFrame != childFrame->GetType())) {
-        DoDeletingFrameSubtree(aFrameManager, aDestroyQueue,
-                               aRemovedFrame, childFrame);
-
+        RECURSE(aRemovedFrame, childFrame);
       } else {
         nsIFrame* outOfFlowFrame =
           nsPlaceholderFrame::GetRealFrameForPlaceholder(childFrame);
   
         // Remove the mapping from the out-of-flow frame to its placeholder.
         aFrameManager->UnregisterPlaceholderFrame((nsPlaceholderFrame*)childFrame);
         // Don't SetOutOfFlowFrame(nsnull) here because the float cache depends
         // on it when the float is removed later on, see bug 348688 comment 6.
@@ -9184,36 +9216,35 @@ DoDeletingFrameSubtree(nsFrameManager* a
         // If aRemovedFrame is an ancestor of the out-of-flow frame, then 
         // the out-of-flow frame will be destroyed by aRemovedFrame.
         if (outOfFlowFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_POPUP ||
             !nsLayoutUtils::IsProperAncestorFrame(aRemovedFrame, outOfFlowFrame)) {
           NS_ASSERTION(aDestroyQueue.IndexOf(outOfFlowFrame) == kNotFound,
                        "out-of-flow is already in the destroy queue");
           aDestroyQueue.AppendElement(outOfFlowFrame);
           // Recurse into the out-of-flow, it is now the aRemovedFrame.
-          DoDeletingFrameSubtree(aFrameManager, aDestroyQueue,
-                                 outOfFlowFrame, outOfFlowFrame);
+          RECURSE(outOfFlowFrame, outOfFlowFrame);
         }
         else {
           // Also recurse into the out-of-flow when it's a descendant of aRemovedFrame
           // since we don't walk those lists, see |childListName| increment below.
-          DoDeletingFrameSubtree(aFrameManager, aDestroyQueue,
-                                 aRemovedFrame, outOfFlowFrame);
+          RECURSE(aRemovedFrame, outOfFlowFrame);
         }
       }
     }
 
     // Move to next child list but skip lists with frames we should have
-    // a placeholder for.
+    // a placeholder for or that contains only next-in-flow overflow containers
+    // (which we walk explicitly above).
     do {
       childListName = aFrame->GetAdditionalChildListName(childListIndex++);
-    } while (IsOutOfFlowList(childListName));
+    } while (IsOutOfFlowList(childListName) ||
+             childListName == nsGkAtoms::overflowContainersList ||
+             childListName == nsGkAtoms::excessOverflowContainersList);
   } while (childListName);
-
-  return NS_OK;
 }
 
 /**
  * Called when a frame is about to be deleted. Calls DoDeletingFrameSubtree()
  * for aFrame and each of its continuing frames
  */
 static nsresult
 DeletingFrameSubtree(nsFrameManager* aFrameManager,
@@ -9237,16 +9268,20 @@ DeletingFrameSubtree(nsFrameManager* aFr
   do {
     DoDeletingFrameSubtree(aFrameManager, destroyQueue, aFrame, aFrame);
 
     // If it's split, then get the continuing frame. Note that we only do
     // this for the top-most frame being deleted. Don't do it if we're
     // recursing over a subtree, because those continuing frames should be
     // found as part of the walk over the top-most frame's continuing frames.
     // Walking them again will make this an N^2/2 algorithm.
+    // The above is true for normal child next-in-flows but not overflow
+    // containers which we do walk because they *can* escape the subtree
+    // we're deleting.  We skip [excess]overflowContainersList where
+    // they live to avoid processing them more than once.
     aFrame = aFrame->GetNextContinuation();
   } while (aFrame);
 
   // Now destroy any out-of-flow frames that have been enqueued for
   // destruction.
   for (PRInt32 i = destroyQueue.Count() - 1; i >= 0; --i) {
     nsIFrame* outOfFlowFrame = static_cast<nsIFrame*>(destroyQueue[i]);
 
