Commit 9170750f authored by tzik's avatar tzik Committed by Commit Bot

Do not cast LifecycleObserver to its subclass before it's constructed

This CL fixes a CFI check failure on the Oilpan incremental marking.

The initialization of ContextLifecycleObserver is done as:
 1. Allocate sufficient memory for the instance
 2. Call GCM constructor
 3. Update the vptr to point LifecycleObserver's vtable
 4. Call the body of LifecycleObserver constructor.
 5. Update the vptr to point ContextLifecycleObserver's vtable
 6. Call the body of ContextLifecycleObserver constructor.

In the step 4, the constructor calls SetContext, which casts the
instance from LO to CLO and stores it to LifecycleNotifier, and that
causes Trace() or GetTraceDescriptor() call on CLO, rather than LO.
Note that the instance is ready as an LO instance, but not ready as an
CLO instance at the moment.
While a virtual method of CLO is being dispatched, CFI checks if the
vtable of the receiver is for CLO or its subclass, but that was not true
as the vptr points LO's vtable until the step 5.

After this CL, LO::Trace() or LO:GetTraceDescriptor() will be called
in SetContext(), rather than CLO::Trace() or CLO::GetTraceDescriptor(),
that should be ready to call before the step 5.

Bug: 854639
Change-Id: Ib27f147099ccb416d5f357fccd401d003de2dcaa
Reviewed-on: https://chromium-review.googlesource.com/1122140
Commit-Queue: Taiju Tsuiki <tzik@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarKeishi Hattori <keishi@chromium.org>
Reviewed-by: default avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572103}
parent b4c74884
...@@ -34,7 +34,9 @@ namespace blink { ...@@ -34,7 +34,9 @@ namespace blink {
void ContextLifecycleNotifier::NotifyResumingPausableObjects() { void ContextLifecycleNotifier::NotifyResumingPausableObjects() {
base::AutoReset<IterationState> scope(&iteration_state_, kAllowingNone); base::AutoReset<IterationState> scope(&iteration_state_, kAllowingNone);
for (ContextLifecycleObserver* observer : observers_) { for (LifecycleObserverBase* observer_base : observers_) {
ContextLifecycleObserver* observer =
static_cast<ContextLifecycleObserver*>(observer_base);
if (observer->ObserverType() != if (observer->ObserverType() !=
ContextLifecycleObserver::kPausableObjectType) ContextLifecycleObserver::kPausableObjectType)
continue; continue;
...@@ -49,7 +51,9 @@ void ContextLifecycleNotifier::NotifyResumingPausableObjects() { ...@@ -49,7 +51,9 @@ void ContextLifecycleNotifier::NotifyResumingPausableObjects() {
void ContextLifecycleNotifier::NotifySuspendingPausableObjects() { void ContextLifecycleNotifier::NotifySuspendingPausableObjects() {
base::AutoReset<IterationState> scope(&iteration_state_, kAllowingNone); base::AutoReset<IterationState> scope(&iteration_state_, kAllowingNone);
for (ContextLifecycleObserver* observer : observers_) { for (LifecycleObserverBase* observer_base : observers_) {
ContextLifecycleObserver* observer =
static_cast<ContextLifecycleObserver*>(observer_base);
if (observer->ObserverType() != if (observer->ObserverType() !=
ContextLifecycleObserver::kPausableObjectType) ContextLifecycleObserver::kPausableObjectType)
continue; continue;
...@@ -65,7 +69,9 @@ void ContextLifecycleNotifier::NotifySuspendingPausableObjects() { ...@@ -65,7 +69,9 @@ void ContextLifecycleNotifier::NotifySuspendingPausableObjects() {
unsigned ContextLifecycleNotifier::PausableObjectCount() const { unsigned ContextLifecycleNotifier::PausableObjectCount() const {
DCHECK(!IsIteratingOverObservers()); DCHECK(!IsIteratingOverObservers());
unsigned pausable_objects = 0; unsigned pausable_objects = 0;
for (ContextLifecycleObserver* observer : observers_) { for (LifecycleObserverBase* observer_base : observers_) {
ContextLifecycleObserver* observer =
static_cast<ContextLifecycleObserver*>(observer_base);
if (observer->ObserverType() != if (observer->ObserverType() !=
ContextLifecycleObserver::kPausableObjectType) ContextLifecycleObserver::kPausableObjectType)
continue; continue;
...@@ -77,7 +83,9 @@ unsigned ContextLifecycleNotifier::PausableObjectCount() const { ...@@ -77,7 +83,9 @@ unsigned ContextLifecycleNotifier::PausableObjectCount() const {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
bool ContextLifecycleNotifier::Contains(PausableObject* object) const { bool ContextLifecycleNotifier::Contains(PausableObject* object) const {
DCHECK(!IsIteratingOverObservers()); DCHECK(!IsIteratingOverObservers());
for (ContextLifecycleObserver* observer : observers_) { for (LifecycleObserverBase* observer_base : observers_) {
ContextLifecycleObserver* observer =
static_cast<ContextLifecycleObserver*>(observer_base);
if (observer->ObserverType() != if (observer->ObserverType() !=
ContextLifecycleObserver::kPausableObjectType) ContextLifecycleObserver::kPausableObjectType)
continue; continue;
......
...@@ -13,28 +13,40 @@ SynchronousMutationNotifier::SynchronousMutationNotifier() = default; ...@@ -13,28 +13,40 @@ SynchronousMutationNotifier::SynchronousMutationNotifier() = default;
void SynchronousMutationNotifier::NotifyChangeChildren( void SynchronousMutationNotifier::NotifyChangeChildren(
const ContainerNode& container) { const ContainerNode& container) {
for (SynchronousMutationObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->DidChangeChildren(container); observer->DidChangeChildren(container);
}
} }
void SynchronousMutationNotifier::NotifyMergeTextNodes( void SynchronousMutationNotifier::NotifyMergeTextNodes(
const Text& node, const Text& node,
const NodeWithIndex& node_to_be_removed_with_index, const NodeWithIndex& node_to_be_removed_with_index,
unsigned old_length) { unsigned old_length) {
for (SynchronousMutationObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->DidMergeTextNodes(node, node_to_be_removed_with_index, observer->DidMergeTextNodes(node, node_to_be_removed_with_index,
old_length); old_length);
}
} }
void SynchronousMutationNotifier::NotifyMoveTreeToNewDocument( void SynchronousMutationNotifier::NotifyMoveTreeToNewDocument(
const Node& root) { const Node& root) {
for (SynchronousMutationObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->DidMoveTreeToNewDocument(root); observer->DidMoveTreeToNewDocument(root);
}
} }
void SynchronousMutationNotifier::NotifySplitTextNode(const Text& node) { void SynchronousMutationNotifier::NotifySplitTextNode(const Text& node) {
for (SynchronousMutationObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->DidSplitTextNode(node); observer->DidSplitTextNode(node);
}
} }
void SynchronousMutationNotifier::NotifyUpdateCharacterData( void SynchronousMutationNotifier::NotifyUpdateCharacterData(
...@@ -42,7 +54,9 @@ void SynchronousMutationNotifier::NotifyUpdateCharacterData( ...@@ -42,7 +54,9 @@ void SynchronousMutationNotifier::NotifyUpdateCharacterData(
unsigned offset, unsigned offset,
unsigned old_length, unsigned old_length,
unsigned new_length) { unsigned new_length) {
for (SynchronousMutationObserver* observer : observers_) { for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->DidUpdateCharacterData(character_data, offset, old_length, observer->DidUpdateCharacterData(character_data, offset, old_length,
new_length); new_length);
} }
...@@ -50,13 +64,19 @@ void SynchronousMutationNotifier::NotifyUpdateCharacterData( ...@@ -50,13 +64,19 @@ void SynchronousMutationNotifier::NotifyUpdateCharacterData(
void SynchronousMutationNotifier::NotifyNodeChildrenWillBeRemoved( void SynchronousMutationNotifier::NotifyNodeChildrenWillBeRemoved(
ContainerNode& container) { ContainerNode& container) {
for (SynchronousMutationObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->NodeChildrenWillBeRemoved(container); observer->NodeChildrenWillBeRemoved(container);
}
} }
void SynchronousMutationNotifier::NotifyNodeWillBeRemoved(Node& node) { void SynchronousMutationNotifier::NotifyNodeWillBeRemoved(Node& node) {
for (SynchronousMutationObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
SynchronousMutationObserver* observer =
static_cast<SynchronousMutationObserver*>(observer_base);
observer->NodeWillBeRemoved(node); observer->NodeWillBeRemoved(node);
}
} }
} // namespace blink } // namespace blink
...@@ -32,8 +32,11 @@ namespace blink { ...@@ -32,8 +32,11 @@ namespace blink {
void PageVisibilityNotifier::NotifyPageVisibilityChanged() { void PageVisibilityNotifier::NotifyPageVisibilityChanged() {
base::AutoReset<IterationState> scope(&iteration_state_, kAllowingNone); base::AutoReset<IterationState> scope(&iteration_state_, kAllowingNone);
for (PageVisibilityObserver* observer : observers_) for (LifecycleObserverBase* observer_base : observers_) {
PageVisibilityObserver* observer =
static_cast<PageVisibilityObserver*>(observer_base);
observer->PageVisibilityChanged(); observer->PageVisibilityChanged();
}
} }
} // namespace blink } // namespace blink
...@@ -33,13 +33,15 @@ ...@@ -33,13 +33,15 @@
namespace blink { namespace blink {
class LifecycleObserverBase;
template <typename T, typename Observer> template <typename T, typename Observer>
class LifecycleNotifier : public GarbageCollectedMixin { class LifecycleNotifier : public GarbageCollectedMixin {
public: public:
virtual ~LifecycleNotifier(); virtual ~LifecycleNotifier();
void AddObserver(Observer*); void AddObserver(LifecycleObserverBase*);
void RemoveObserver(Observer*); void RemoveObserver(LifecycleObserverBase*);
// notifyContextDestroyed() should be explicitly dispatched from an // notifyContextDestroyed() should be explicitly dispatched from an
// observed context to detach its observers, and if the observer kind // observed context to detach its observers, and if the observer kind
...@@ -61,7 +63,7 @@ class LifecycleNotifier : public GarbageCollectedMixin { ...@@ -61,7 +63,7 @@ class LifecycleNotifier : public GarbageCollectedMixin {
T* Context() { return static_cast<T*>(this); } T* Context() { return static_cast<T*>(this); }
using ObserverSet = HeapHashSet<WeakMember<Observer>>; using ObserverSet = HeapHashSet<WeakMember<LifecycleObserverBase>>;
enum IterationState { enum IterationState {
kAllowingNone = 0, kAllowingNone = 0,
...@@ -135,7 +137,8 @@ inline void LifecycleNotifier<T, Observer>::NotifyContextDestroyed() { ...@@ -135,7 +137,8 @@ inline void LifecycleNotifier<T, Observer>::NotifyContextDestroyed() {
base::AutoReset<IterationState> scope(&iteration_state_, kAllowingRemoval); base::AutoReset<IterationState> scope(&iteration_state_, kAllowingRemoval);
ObserverSet observers; ObserverSet observers;
observers_.swap(observers); observers_.swap(observers);
for (Observer* observer : observers) { for (LifecycleObserverBase* observer_base : observers) {
Observer* observer = static_cast<Observer*>(observer_base);
DCHECK(observer->LifecycleContext() == Context()); DCHECK(observer->LifecycleContext() == Context());
ContextDestroyedNotifier<Observer, T>::Call(observer, Context()); ContextDestroyedNotifier<Observer, T>::Call(observer, Context());
observer->ClearContext(); observer->ClearContext();
...@@ -143,13 +146,15 @@ inline void LifecycleNotifier<T, Observer>::NotifyContextDestroyed() { ...@@ -143,13 +146,15 @@ inline void LifecycleNotifier<T, Observer>::NotifyContextDestroyed() {
} }
template <typename T, typename Observer> template <typename T, typename Observer>
inline void LifecycleNotifier<T, Observer>::AddObserver(Observer* observer) { inline void LifecycleNotifier<T, Observer>::AddObserver(
LifecycleObserverBase* observer) {
CHECK(iteration_state_ & kAllowingAddition); CHECK(iteration_state_ & kAllowingAddition);
observers_.insert(observer); observers_.insert(observer);
} }
template <typename T, typename Observer> template <typename T, typename Observer>
inline void LifecycleNotifier<T, Observer>::RemoveObserver(Observer* observer) { inline void LifecycleNotifier<T, Observer>::RemoveObserver(
LifecycleObserverBase* observer) {
// If immediate removal isn't currently allowed, // If immediate removal isn't currently allowed,
// |observer| is recorded for pending removal. // |observer| is recorded for pending removal.
if (iteration_state_ & kAllowPendingRemoval) { if (iteration_state_ & kAllowPendingRemoval) {
......
...@@ -34,8 +34,10 @@ namespace blink { ...@@ -34,8 +34,10 @@ namespace blink {
template <typename Context, typename Observer> template <typename Context, typename Observer>
class LifecycleNotifier; class LifecycleNotifier;
class LifecycleObserverBase : public GarbageCollectedMixin {};
template <typename Context, typename Observer> template <typename Context, typename Observer>
class LifecycleObserver : public GarbageCollectedMixin { class LifecycleObserver : public LifecycleObserverBase {
public: public:
void Trace(blink::Visitor* visitor) override { void Trace(blink::Visitor* visitor) override {
visitor->Trace(lifecycle_context_); visitor->Trace(lifecycle_context_);
...@@ -64,15 +66,13 @@ inline void LifecycleObserver<Context, Observer>::SetContext(Context* context) { ...@@ -64,15 +66,13 @@ inline void LifecycleObserver<Context, Observer>::SetContext(Context* context) {
return; return;
if (lifecycle_context_) { if (lifecycle_context_) {
static_cast<Notifier*>(lifecycle_context_) static_cast<Notifier*>(lifecycle_context_)->RemoveObserver(this);
->RemoveObserver(static_cast<Observer*>(this));
} }
lifecycle_context_ = context; lifecycle_context_ = context;
if (lifecycle_context_) { if (lifecycle_context_) {
static_cast<Notifier*>(lifecycle_context_) static_cast<Notifier*>(lifecycle_context_)->AddObserver(this);
->AddObserver(static_cast<Observer*>(this));
} }
} }
......
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