Commit d0b94ee2 authored by Keishi Hattori's avatar Keishi Hattori Committed by Commit Bot

Add CHECK for Layout::Destroy() called inside a finalizer

LayoutObject::Destroy() should not be called inside a finalizer. This becomes dangerous when we migrate LayoutObje ct to Oilpan as finalizers are not allowed to access other on-heap objects.

This CL adds AllowDestroyingLayoutObjectInFinalizerScope to mark certain SVGImage() as exempt from this CHECK. This is OK as SVGImage is retaining the LayoutObject via a Persistent and so it is guaranteed to survive the current GC cycle.

Bug: 1030176
Change-Id: Ibdd0a29e7630747ea118d92d442776cf1bac8537
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352294Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Commit-Queue: Keishi Hattori <keishi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798217}
parent 30285124
...@@ -149,6 +149,18 @@ LayoutObject* FindAncestorByPredicate(const LayoutObject* descendant, ...@@ -149,6 +149,18 @@ LayoutObject* FindAncestorByPredicate(const LayoutObject* descendant,
} // namespace } // namespace
static int g_allow_destroying_layout_object_in_finalizer = 0;
AllowDestroyingLayoutObjectInFinalizerScope::
AllowDestroyingLayoutObjectInFinalizerScope() {
++g_allow_destroying_layout_object_in_finalizer;
}
AllowDestroyingLayoutObjectInFinalizerScope::
~AllowDestroyingLayoutObjectInFinalizerScope() {
CHECK_GT(g_allow_destroying_layout_object_in_finalizer, 0);
--g_allow_destroying_layout_object_in_finalizer;
}
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
LayoutObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope( LayoutObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(
...@@ -3560,6 +3572,9 @@ void LayoutObject::DestroyAndCleanupAnonymousWrappers() { ...@@ -3560,6 +3572,9 @@ void LayoutObject::DestroyAndCleanupAnonymousWrappers() {
} }
void LayoutObject::Destroy() { void LayoutObject::Destroy() {
CHECK(g_allow_destroying_layout_object_in_finalizer ||
!ThreadState::Current()->InAtomicSweepingPause());
// Mark as being destroyed to avoid trouble with merges in |RemoveChild()| and // Mark as being destroyed to avoid trouble with merges in |RemoveChild()| and
// other house keepings. // other house keepings.
bitfields_.SetBeingDestroyed(true); bitfields_.SetBeingDestroyed(true);
......
...@@ -135,6 +135,18 @@ struct AnnotatedRegionValue { ...@@ -135,6 +135,18 @@ struct AnnotatedRegionValue {
const int kShowTreeCharacterOffset = 39; const int kShowTreeCharacterOffset = 39;
#endif #endif
// Usually calling LayooutObject::Destroy() is banned. This scope can be used to
// exclude certain functions like ~SVGImage() from this rule. This is allowed
// when a Persistent is guaranteeing to keep the LayoutObject alive for that GC
// cycle.
class AllowDestroyingLayoutObjectInFinalizerScope {
STACK_ALLOCATED();
public:
AllowDestroyingLayoutObjectInFinalizerScope();
~AllowDestroyingLayoutObjectInFinalizerScope();
};
// LayoutObject is the base class for all layout tree objects. // LayoutObject is the base class for all layout tree objects.
// //
// LayoutObjects form a tree structure that is a close mapping of the DOM tree. // LayoutObjects form a tree structure that is a close mapping of the DOM tree.
......
...@@ -135,6 +135,8 @@ TEST_P(ValidationMessageOverlayDelegateTest, ...@@ -135,6 +135,8 @@ TEST_P(ValidationMessageOverlayDelegateTest,
EXPECT_EQ(external_clock.CurrentTime(), internal_clock.CurrentTime()); EXPECT_EQ(external_clock.CurrentTime(), internal_clock.CurrentTime());
GetPage().SetValidationMessageClientForTesting(original_client); GetPage().SetValidationMessageClientForTesting(original_client);
static_cast<ValidationMessageClient*>(client)->WillBeDestroyed();
} }
} // namespace blink } // namespace blink
...@@ -168,6 +168,8 @@ SVGImage::SVGImage(ImageObserver* observer, bool is_multipart) ...@@ -168,6 +168,8 @@ SVGImage::SVGImage(ImageObserver* observer, bool is_multipart)
has_pending_timeline_rewind_(false) {} has_pending_timeline_rewind_(false) {}
SVGImage::~SVGImage() { SVGImage::~SVGImage() {
AllowDestroyingLayoutObjectInFinalizerScope scope;
if (frame_client_) if (frame_client_)
frame_client_->ClearImage(); frame_client_->ClearImage();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment