Skip to content

Commit

Permalink
Bug 1393791 - Stop unbinding native-anonymous content off a script ru…
Browse files Browse the repository at this point in the history
…nner. r=emilio

The failure mode in the attached crashtest is an inconsistency in the flattened
tree. Specifically, we null out mVideoControls in an nsVideoFrame, but defer
the UnbindFromTree call on that NAC element, which measn that its mParent still
points to the nsVideoFrame's mContent. Because all this stuff runs off of script
runners, and the anonymous content destroyer is not guaranteed to run before
other potential script runners, we end up running arbitrary script while the
tree mismatch exists. This script calls back into ProcessPendingRestyles, which
causes trouble.

We could build a separate deferral mechanism, but it's not clear that we actually
need to defer the unbind anymore. The deferred unbind was added in bug 489008,
which predated a lot of simplifications in layout/dom interaction.

MozReview-Commit-ID: 1JYAhiXKVJC
  • Loading branch information
bholley committed Aug 27, 2017
1 parent 9631dd3 commit 8fb4fb3
Show file tree
Hide file tree
Showing 22 changed files with 54 additions and 80 deletions.
46 changes: 0 additions & 46 deletions dom/base/nsContentUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5412,52 +5412,6 @@ nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
return nodeAsContent->GetBindingParent() == aContent->GetBindingParent();
}

class AnonymousContentDestroyer : public Runnable {
public:
explicit AnonymousContentDestroyer(nsCOMPtr<nsIContent>* aContent)
: mozilla::Runnable("AnonymousContentDestroyer")
{
mContent.swap(*aContent);
mParent = mContent->GetParent();
mDoc = mContent->OwnerDoc();
}
explicit AnonymousContentDestroyer(nsCOMPtr<Element>* aElement)
: mozilla::Runnable("AnonymousContentDestroyer")
{
mContent = aElement->forget();
mParent = mContent->GetParent();
mDoc = mContent->OwnerDoc();
}
NS_IMETHOD Run() override {
mContent->UnbindFromTree();
return NS_OK;
}
private:
nsCOMPtr<nsIContent> mContent;
// Hold strong refs to the parent content and document so that they
// don't die unexpectedly
nsCOMPtr<nsIDocument> mDoc;
nsCOMPtr<nsIContent> mParent;
};

/* static */
void
nsContentUtils::DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent)
{
if (*aContent) {
AddScriptRunner(new AnonymousContentDestroyer(aContent));
}
}

/* static */
void
nsContentUtils::DestroyAnonymousContent(nsCOMPtr<Element>* aElement)
{
if (*aElement) {
AddScriptRunner(new AnonymousContentDestroyer(aElement));
}
}

/* static */
void
nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
Expand Down
6 changes: 0 additions & 6 deletions dom/base/nsContentUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1672,12 +1672,6 @@ class nsContentUtils
*/
static void DestroyMatchString(void* aData);

/**
* Unbinds the content from the tree and nulls it out if it's not null.
*/
static void DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent);
static void DestroyAnonymousContent(nsCOMPtr<Element>* aElement);

/*
* Notify when the first XUL menu is opened and when the all XUL menus are
* closed. At opening, aInstalling should be TRUE, otherwise, it should be
Expand Down
6 changes: 3 additions & 3 deletions dom/html/nsTextEditorState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2264,9 +2264,9 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
// Unbind the anonymous content from the tree.
// We actually hold a reference to the content nodes so that
// they're not actually destroyed.
nsContentUtils::DestroyAnonymousContent(&rootNode);
nsContentUtils::DestroyAnonymousContent(&mPlaceholderDiv);
nsContentUtils::DestroyAnonymousContent(&mPreviewDiv);
aFrame->DestroyAnonymousContent(rootNode.forget());
aFrame->DestroyAnonymousContent(mPlaceholderDiv.forget());
aFrame->DestroyAnonymousContent(mPreviewDiv.forget());
}

nsresult
Expand Down
15 changes: 15 additions & 0 deletions layout/base/nsFrameManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,21 @@ nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
}
}

void
nsFrameManager::DestroyAnonymousContent(already_AddRefed<nsIContent> aContent)
{
nsCOMPtr<nsIContent> content = aContent;
if (content) {
// Invoke ClearAllMapsFor before unbinding from the tree. When we unbind,
// we remove the mPrimaryFrame pointer, which is used by the frame
// teardown code to determine whether to invoke ClearAllMapsFor or not.
// These maps will go away when we drop support for the old style system.
ClearAllMapsFor(content);

content->UnbindFromTree();
}
}

//----------------------------------------------------------------------

nsFrameManagerBase::UndisplayedMap::UndisplayedMap()
Expand Down
2 changes: 2 additions & 0 deletions layout/base/nsFrameManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ class nsFrameManager : public nsFrameManagerBase

void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);

void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);

protected:
static nsIContent* ParentForUndisplayedMap(const nsIContent* aContent);

Expand Down
2 changes: 1 addition & 1 deletion layout/forms/nsColorControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
void nsColorControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
nsContentUtils::DestroyAnonymousContent(&mColorContent);
DestroyAnonymousContent(mColorContent.forget());
nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot);
}

Expand Down
4 changes: 2 additions & 2 deletions layout/forms/nsComboboxControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1418,8 +1418,8 @@ nsComboboxControlFrame::DestroyFrom(nsIFrame* aDestructRoot)

// Cleanup frames in popup child list
mPopupFrames.DestroyFramesFrom(aDestructRoot);
nsContentUtils::DestroyAnonymousContent(&mDisplayContent);
nsContentUtils::DestroyAnonymousContent(&mButtonContent);
DestroyAnonymousContent(mDisplayContent.forget());
DestroyAnonymousContent(mButtonContent.forget());
nsBlockFrame::DestroyFrom(aDestructRoot);
}

Expand Down
2 changes: 1 addition & 1 deletion layout/forms/nsDateTimeControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ nsDateTimeControlFrame::nsDateTimeControlFrame(nsStyleContext* aContext)
void
nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsContentUtils::DestroyAnonymousContent(&mInputAreaContent);
DestroyAnonymousContent(mInputAreaContent.forget());
nsContainerFrame::DestroyFrom(aDestructRoot);
}

Expand Down
4 changes: 2 additions & 2 deletions layout/forms/nsFileControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ nsFileControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
mMouseListener, false);
}

nsContentUtils::DestroyAnonymousContent(&mTextContent);
nsContentUtils::DestroyAnonymousContent(&mBrowseFilesOrDirs);
DestroyAnonymousContent(mTextContent.forget());
DestroyAnonymousContent(mBrowseFilesOrDirs.forget());

mMouseListener->ForgetFrame();
nsBlockFrame::DestroyFrom(aDestructRoot);
Expand Down
2 changes: 1 addition & 1 deletion layout/forms/nsGfxButtonControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsGfxButtonControlFrame)

void nsGfxButtonControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsContentUtils::DestroyAnonymousContent(&mTextContent);
DestroyAnonymousContent(mTextContent.forget());
nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot);
}

Expand Down
2 changes: 1 addition & 1 deletion layout/forms/nsMeterFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ nsMeterFrame::DestroyFrom(nsIFrame* aDestructRoot)
"nsMeterFrame should not have continuations; if it does we "
"need to call RegUnregAccessKey only for the first.");
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
nsContentUtils::DestroyAnonymousContent(&mBarDiv);
DestroyAnonymousContent(mBarDiv.forget());
nsContainerFrame::DestroyFrom(aDestructRoot);
}
Expand Down
2 changes: 1 addition & 1 deletion layout/forms/nsNumberControlFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ nsNumberControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
"nsNumberControlFrame should not have continuations; if it does we "
"need to call RegUnregAccessKey only for the first");
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
nsContentUtils::DestroyAnonymousContent(&mOuterWrapper);
DestroyAnonymousContent(mOuterWrapper.forget());
nsContainerFrame::DestroyFrom(aDestructRoot);
}
Expand Down
2 changes: 1 addition & 1 deletion layout/forms/nsProgressFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ nsProgressFrame::DestroyFrom(nsIFrame* aDestructRoot)
"nsProgressFrame should not have continuations; if it does we "
"need to call RegUnregAccessKey only for the first.");
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
nsContentUtils::DestroyAnonymousContent(&mBarDiv);
DestroyAnonymousContent(mBarDiv.forget());
nsContainerFrame::DestroyFrom(aDestructRoot);
}
Expand Down
6 changes: 3 additions & 3 deletions layout/forms/nsRangeFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ nsRangeFrame::DestroyFrom(nsIFrame* aDestructRoot)
mContent->RemoveEventListener(NS_LITERAL_STRING("touchstart"), mDummyTouchListener, false);
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
nsContentUtils::DestroyAnonymousContent(&mTrackDiv);
nsContentUtils::DestroyAnonymousContent(&mProgressDiv);
nsContentUtils::DestroyAnonymousContent(&mThumbDiv);
DestroyAnonymousContent(mTrackDiv.forget());
DestroyAnonymousContent(mProgressDiv.forget());
DestroyAnonymousContent(mThumbDiv.forget());
nsContainerFrame::DestroyFrom(aDestructRoot);
}
Expand Down
2 changes: 1 addition & 1 deletion layout/generic/DetailsFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ DetailsFrame::CheckValidMainSummary(const nsFrameList& aFrameList) const
void
DetailsFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsContentUtils::DestroyAnonymousContent(&mDefaultSummary);
DestroyAnonymousContent(mDefaultSummary.forget());
nsBlockFrame::DestroyFrom(aDestructRoot);
}

Expand Down
2 changes: 1 addition & 1 deletion layout/generic/nsCanvasFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot)
content->SetContentNode(clonedElement->AsElement());
}
}
nsContentUtils::DestroyAnonymousContent(&mCustomContentContainer);
DestroyAnonymousContent(mCustomContentContainer.forget());

nsContainerFrame::DestroyFrom(aDestructRoot);
}
Expand Down
7 changes: 7 additions & 0 deletions layout/generic/nsFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ nsReflowStatus::UpdateTruncated(const ReflowInput& aReflowInput,
}
}

void
nsIFrame::DestroyAnonymousContent(already_AddRefed<nsIContent> aContent)
{
PresContext()->PresShell()->FrameConstructor()
->DestroyAnonymousContent(mozilla::Move(aContent));
}

// Formerly the nsIFrameDebug interface

#ifdef DEBUG
Expand Down
8 changes: 4 additions & 4 deletions layout/generic/nsGfxScrollFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4607,10 +4607,10 @@ ScrollFrameHelper::Destroy()
}

// Unbind any content created in CreateAnonymousContent from the tree
nsContentUtils::DestroyAnonymousContent(&mHScrollbarContent);
nsContentUtils::DestroyAnonymousContent(&mVScrollbarContent);
nsContentUtils::DestroyAnonymousContent(&mScrollCornerContent);
nsContentUtils::DestroyAnonymousContent(&mResizerContent);
mOuter->DestroyAnonymousContent(mHScrollbarContent.forget());
mOuter->DestroyAnonymousContent(mVScrollbarContent.forget());
mOuter->DestroyAnonymousContent(mScrollCornerContent.forget());
mOuter->DestroyAnonymousContent(mResizerContent.forget());

if (mPostedReflowCallback) {
mOuter->PresContext()->PresShell()->CancelReflowCallback(this);
Expand Down
2 changes: 2 additions & 0 deletions layout/generic/nsIFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -4026,6 +4026,8 @@ class nsIFrame : public nsQueryFrame

DisplayItemArray& DisplayItemData() { return mDisplayItemData; }

void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);

protected:

/**
Expand Down
6 changes: 3 additions & 3 deletions layout/generic/nsVideoFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@ nsVideoFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
void
nsVideoFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsContentUtils::DestroyAnonymousContent(&mCaptionDiv);
nsContentUtils::DestroyAnonymousContent(&mVideoControls);
nsContentUtils::DestroyAnonymousContent(&mPosterImage);
DestroyAnonymousContent(mCaptionDiv.forget());
DestroyAnonymousContent(mVideoControls.forget());
DestroyAnonymousContent(mPosterImage.forget());
nsContainerFrame::DestroyFrom(aDestructRoot);
}

Expand Down
2 changes: 1 addition & 1 deletion layout/svg/nsSVGUseFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ nsSVGUseFrame::AttributeChanged(int32_t aNameSpaceID,
void
nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsContentUtils::DestroyAnonymousContent(&mContentClone);
DestroyAnonymousContent(mContentClone.forget());
nsSVGGFrame::DestroyFrom(aDestructRoot);
}

Expand Down
4 changes: 2 additions & 2 deletions layout/xul/nsDocElementBoxFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ NS_IMPL_FRAMEARENA_HELPERS(nsDocElementBoxFrame)
void
nsDocElementBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsContentUtils::DestroyAnonymousContent(&mPopupgroupContent);
nsContentUtils::DestroyAnonymousContent(&mTooltipContent);
DestroyAnonymousContent(mPopupgroupContent.forget());
DestroyAnonymousContent(mTooltipContent.forget());
nsBoxFrame::DestroyFrom(aDestructRoot);
}

Expand Down

0 comments on commit 8fb4fb3

Please sign in to comment.