diff --git a/layout/generic/crashtests/606642.xhtml b/layout/generic/crashtests/606642.xhtml new file mode 100644 index 000000000000..9113b7d71828 --- /dev/null +++ b/layout/generic/crashtests/606642.xhtml @@ -0,0 +1,16 @@ + + + + + +
+ diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 6b575fe8b8d7..923619da9731 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -383,6 +383,7 @@ load 603510-1.html load 604314-1.html load 604843.html load 605340.html +load 606642.xhtml load 621424-1.html load 621841-1.html load 645072-1.html diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 4605c6e9dd8c..80a0be5777b8 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -216,6 +216,27 @@ nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot) } } +void +nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot, + FramePropertyTable* aPropTable, + const FramePropertyDescriptor* aProp) +{ + // Note that the last frame can be removed through another route and thus + // delete the property -- that's why we fetch the property again before + // removing each frame rather than fetching it once and iterating the list. + while (nsFrameList* frameList = + static_cast(aPropTable->Get(this, aProp))) { + nsIFrame* frame = frameList->RemoveFirstChild(); + if (MOZ_LIKELY(frame)) { + frame->DestroyFrom(aDestructRoot); + } else { + aPropTable->Remove(this, aProp); + delete frameList; + return; + } + } +} + void nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot) { @@ -235,15 +256,11 @@ nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot) DestroyOverflowList(prescontext, aDestructRoot); if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) { - nsFrameList* frameList = - RemovePropTableFrames(prescontext, OverflowContainersProperty()); - if (frameList) - frameList->DestroyFrom(aDestructRoot); - - frameList = RemovePropTableFrames(prescontext, - ExcessOverflowContainersProperty()); - if (frameList) - frameList->DestroyFrom(aDestructRoot); + FramePropertyTable* props = prescontext->PropertyTable(); + SafelyDestroyFrameListProp(aDestructRoot, props, + OverflowContainersProperty()); + SafelyDestroyFrameListProp(aDestructRoot, props, + ExcessOverflowContainersProperty()); } // Destroy the frame and remove the flow pointers diff --git a/layout/generic/nsContainerFrame.h b/layout/generic/nsContainerFrame.h index 5880f1df89e4..b1b7eb56a2ef 100644 --- a/layout/generic/nsContainerFrame.h +++ b/layout/generic/nsContainerFrame.h @@ -25,6 +25,9 @@ #define NS_FRAME_INVALIDATE_ON_MOVE 0x0010 class nsOverflowContinuationTracker; +namespace mozilla { +class FramePropertyTable; +} // Some macros for container classes to do sanity checking on // width/height/x/y values computed during reflow. @@ -514,6 +517,16 @@ protected: nsresult SetPropTableFrames(nsPresContext* aPresContext, nsFrameList* aFrameList, const FramePropertyDescriptor* aProperty); + + /** + * Safely destroy the frames on the nsFrameList stored on aProp for this + * frame then remove the property and delete the frame list. + * Nothing happens if the property doesn't exist. + */ + void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot, + mozilla::FramePropertyTable* aPropTable, + const FramePropertyDescriptor* aProp); + // ========================================================================== nsFrameList mFrames; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index f7742bf7da4a..2f950500b2ec 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -618,6 +618,7 @@ protected: virtual void DestroyFrom(nsIFrame* aDestructRoot) = 0; friend class nsFrameList; // needed to pass aDestructRoot through to children friend class nsLineBox; // needed to pass aDestructRoot through to children + friend class nsContainerFrame; // needed to pass aDestructRoot through to children public: /**