Bug 786740. When destroying all the frames in a line list, keep the line list and frame list valid at each step in case someone tries to walk the frame tree during frame destruction. r=mats

This commit is contained in:
Robert O'Callahan
2012-10-15 14:34:23 +13:00
parent 7f5d9993b0
commit fece33de51
5 changed files with 55 additions and 35 deletions

View File

@@ -353,38 +353,28 @@ nsLineBox::CachedIsEmpty()
void
nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
nsIFrame* aDestructRoot)
nsIFrame* aDestructRoot, nsFrameList* aFrames)
{
if (! aLines.empty()) {
// Delete our child frames before doing anything else. In particular
// we do all of this before our base class releases it's hold on the
// view.
#ifdef DEBUG
int32_t numFrames = 0;
#endif
for (nsIFrame* child = aLines.front()->mFirstChild; child; ) {
nsIFrame* nextChild = child->GetNextSibling();
child->SetNextSibling(nullptr);
child->DestroyFrom((aDestructRoot) ? aDestructRoot : child);
child = nextChild;
#ifdef DEBUG
numFrames++;
#endif
nsIPresShell* shell = aPresContext->PresShell();
// Keep our line list and frame list up to date as we
// remove frames, in case something wants to traverse the
// frame tree while we're destroying.
while (!aLines.empty()) {
nsLineBox* line = aLines.front();
if (NS_UNLIKELY(line->mFlags.mHasHashedFrames)) {
line->SwitchToCounter(); // Avoid expensive has table removals.
}
while (line->GetChildCount() > 0) {
nsIFrame* child = aFrames->RemoveFirstChild();
MOZ_ASSERT(child == line->mFirstChild, "Lines out of sync");
line->mFirstChild = aFrames->FirstChild();
line->NoteFrameRemoved(child);
child->DestroyFrom(aDestructRoot);
}
nsIPresShell *shell = aPresContext->PresShell();
do {
nsLineBox* line = aLines.front();
#ifdef DEBUG
numFrames -= line->GetChildCount();
#endif
aLines.pop_front();
line->Destroy(shell);
} while (! aLines.empty());
#ifdef DEBUG
NS_ASSERTION(numFrames == 0, "number of frames deleted does not match");
#endif
aLines.pop_front();
line->Destroy(shell);
}
}