mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 1337537 - Assert that runnables labeled with a given TabGroup never touch other TabGroups (r=ehsan)
MozReview-Commit-ID: sOdn9e5f57
This commit is contained in:
parent
c46113590f
commit
1ae37fef66
@ -70,5 +70,11 @@ DocGroup::AbstractMainThreadForImpl(TaskCategory aCategory)
|
||||
return mTabGroup->AbstractMainThreadFor(aCategory);
|
||||
}
|
||||
|
||||
bool*
|
||||
DocGroup::GetValidAccessPtr()
|
||||
{
|
||||
return mTabGroup->GetValidAccessPtr();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/Dispatcher.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
@ -34,8 +35,6 @@ namespace dom {
|
||||
// (through its DocGroups) the documents from one or more tabs related by
|
||||
// window.opener. A DocGroup is a member of exactly one TabGroup.
|
||||
|
||||
class TabGroup;
|
||||
|
||||
class DocGroup final : public Dispatcher
|
||||
{
|
||||
public:
|
||||
@ -76,6 +75,17 @@ public:
|
||||
|
||||
virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
|
||||
|
||||
// Ensure that it's valid to access the DocGroup at this time.
|
||||
void ValidateAccess() const
|
||||
{
|
||||
mTabGroup->ValidateAccess();
|
||||
}
|
||||
|
||||
// Return a pointer that can be continually checked to see if access to this
|
||||
// DocGroup is valid. This pointer should live at least as long as the
|
||||
// DocGroup.
|
||||
bool* GetValidAccessPtr();
|
||||
|
||||
private:
|
||||
virtual AbstractThread*
|
||||
AbstractMainThreadForImpl(TaskCategory aCategory) override;
|
||||
|
@ -56,6 +56,7 @@ private:
|
||||
};
|
||||
|
||||
typedef nsTHashtable<HashEntry> DocGroupMap;
|
||||
|
||||
public:
|
||||
typedef DocGroupMap::Iterator Iterator;
|
||||
|
||||
|
@ -4987,6 +4987,14 @@ nsDocument::MaybeEndOutermostXBLUpdate()
|
||||
void
|
||||
nsDocument::BeginUpdate(nsUpdateType aUpdateType)
|
||||
{
|
||||
// If the document is going away, then it's probably okay to do things to it
|
||||
// in the wrong DocGroup. We're unlikely to run JS or do anything else
|
||||
// observable at this point. We reach this point when cycle collecting a
|
||||
// <link> element and the unlink code removes a style sheet.
|
||||
if (mDocGroup && !mIsGoingAway) {
|
||||
mDocGroup->ValidateAccess();
|
||||
}
|
||||
|
||||
if (mUpdateNestLevel == 0 && !mInXBLUpdate) {
|
||||
mInXBLUpdate = true;
|
||||
BindingManager()->BeginOutermostUpdate();
|
||||
@ -7842,6 +7850,10 @@ nsDocument::GetExistingListenerManager() const
|
||||
nsresult
|
||||
nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
if (mDocGroup && aVisitor.mEvent->mMessage != eVoidEvent) {
|
||||
mDocGroup->ValidateAccess();
|
||||
}
|
||||
|
||||
aVisitor.mCanHandle = true;
|
||||
// FIXME! This is a hack to make middle mouse paste working also in Editor.
|
||||
// Bug 329119
|
||||
|
@ -3148,6 +3148,17 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
newInnerWindow->mChromeEventHandler = mChromeEventHandler;
|
||||
}
|
||||
|
||||
// Ask the JS engine to assert that it's valid to access our DocGroup whenever
|
||||
// it runs JS code for this compartment. We skip the check if this window is
|
||||
// for chrome JS or an add-on.
|
||||
nsCOMPtr<nsIPrincipal> principal = mDoc->NodePrincipal();
|
||||
nsString addonId;
|
||||
principal->GetAddonId(addonId);
|
||||
if (GetDocGroup() && !nsContentUtils::IsSystemPrincipal(principal) && addonId.IsEmpty()) {
|
||||
js::SetCompartmentValidAccessPtr(cx, newInnerGlobal,
|
||||
newInnerWindow->GetDocGroup()->GetValidAccessPtr());
|
||||
}
|
||||
|
||||
nsJSContext::PokeGC(JS::gcreason::SET_NEW_DOCUMENT, GetWrapperPreserveColor());
|
||||
kungFuDeathGrip->DidInitializeContext();
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/Dispatcher.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsINamed.h"
|
||||
@ -15,6 +16,21 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
class ValidatingDispatcher::Runnable final : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||
ValidatingDispatcher* aDispatcher);
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
RefPtr<ValidatingDispatcher> mDispatcher;
|
||||
};
|
||||
|
||||
/* DispatcherEventTarget */
|
||||
|
||||
namespace {
|
||||
|
||||
#define NS_DISPATCHEREVENTTARGET_IID \
|
||||
@ -102,7 +118,10 @@ Dispatcher::UnlabeledDispatch(const char* aName,
|
||||
}
|
||||
}
|
||||
|
||||
ValidatingDispatcher* ValidatingDispatcher::sRunningDispatcher;
|
||||
|
||||
ValidatingDispatcher::ValidatingDispatcher()
|
||||
: mAccessValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -111,7 +130,7 @@ ValidatingDispatcher::Dispatch(const char* aName,
|
||||
TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
return UnlabeledDispatch(aName, aCategory, Move(aRunnable));
|
||||
return LabeledDispatch(aName, aCategory, Move(aRunnable));
|
||||
}
|
||||
|
||||
nsIEventTarget*
|
||||
@ -182,3 +201,70 @@ ValidatingDispatcher::FromEventTarget(nsIEventTarget* aEventTarget)
|
||||
}
|
||||
return target->Dispatcher();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ValidatingDispatcher::LabeledDispatch(const char* aName,
|
||||
TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
if (XRE_IsContentProcess()) {
|
||||
runnable = new Runnable(runnable.forget(), this);
|
||||
}
|
||||
return UnlabeledDispatch(aName, aCategory, runnable.forget());
|
||||
}
|
||||
|
||||
void
|
||||
ValidatingDispatcher::SetValidatingAccess(ValidationType aType)
|
||||
{
|
||||
sRunningDispatcher = aType == StartValidation ? this : nullptr;
|
||||
mAccessValid = aType == StartValidation;
|
||||
|
||||
dom::AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
js::EnableAccessValidation(jsapi.cx(), !!sRunningDispatcher);
|
||||
}
|
||||
|
||||
ValidatingDispatcher::Runnable::Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||
ValidatingDispatcher* aDispatcher)
|
||||
: mRunnable(Move(aRunnable)),
|
||||
mDispatcher(aDispatcher)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ValidatingDispatcher::Runnable::Run()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDispatcher->SetValidatingAccess(StartValidation);
|
||||
|
||||
nsresult result = mRunnable->Run();
|
||||
|
||||
// The runnable's destructor can have side effects, so try to execute it in
|
||||
// the scope of the TabGroup.
|
||||
mRunnable = nullptr;
|
||||
|
||||
mDispatcher->SetValidatingAccess(EndValidation);
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidatingDispatcher::AutoProcessEvent::AutoProcessEvent()
|
||||
: mPrevRunningDispatcher(ValidatingDispatcher::sRunningDispatcher)
|
||||
{
|
||||
ValidatingDispatcher* prev = sRunningDispatcher;
|
||||
if (prev) {
|
||||
MOZ_ASSERT(prev->mAccessValid);
|
||||
prev->SetValidatingAccess(EndValidation);
|
||||
}
|
||||
}
|
||||
|
||||
ValidatingDispatcher::AutoProcessEvent::~AutoProcessEvent()
|
||||
{
|
||||
MOZ_ASSERT(!sRunningDispatcher);
|
||||
|
||||
ValidatingDispatcher* prev = mPrevRunningDispatcher;
|
||||
if (prev) {
|
||||
prev->SetValidatingAccess(StartValidation);
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,26 @@ class ValidatingDispatcher : public Dispatcher
|
||||
public:
|
||||
ValidatingDispatcher();
|
||||
|
||||
class MOZ_STACK_CLASS AutoProcessEvent final {
|
||||
public:
|
||||
AutoProcessEvent();
|
||||
~AutoProcessEvent();
|
||||
|
||||
private:
|
||||
ValidatingDispatcher* mPrevRunningDispatcher;
|
||||
};
|
||||
|
||||
// Ensure that it's valid to access the TabGroup at this time.
|
||||
void ValidateAccess() const
|
||||
{
|
||||
MOZ_ASSERT(!sRunningDispatcher || mAccessValid);
|
||||
}
|
||||
|
||||
class Runnable;
|
||||
friend class Runnable;
|
||||
|
||||
bool* GetValidAccessPtr() { return &mAccessValid; }
|
||||
|
||||
nsresult Dispatch(const char* aName,
|
||||
TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
||||
@ -87,9 +107,22 @@ protected:
|
||||
// function returns |dispatcher|.
|
||||
static ValidatingDispatcher* FromEventTarget(nsIEventTarget* aEventTarget);
|
||||
|
||||
nsresult LabeledDispatch(const char* aName,
|
||||
TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
void CreateEventTargets(bool aNeedValidation);
|
||||
void Shutdown();
|
||||
|
||||
enum ValidationType {
|
||||
StartValidation,
|
||||
EndValidation,
|
||||
};
|
||||
void SetValidatingAccess(ValidationType aType);
|
||||
|
||||
static ValidatingDispatcher* sRunningDispatcher;
|
||||
bool mAccessValid;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mEventTargets[size_t(TaskCategory::Count)];
|
||||
RefPtr<AbstractThread> mAbstractThreads[size_t(TaskCategory::Count)];
|
||||
};
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsQueryObject.h"
|
||||
#include "pratom.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/Dispatcher.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/HangMonitor.h"
|
||||
@ -1196,8 +1197,10 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
|
||||
// and repeat the nested event loop since its state change hasn't happened yet.
|
||||
bool reallyWait = aMayWait && (mNestedEventLoopDepth > 0 || !ShuttingDown());
|
||||
|
||||
Maybe<ValidatingDispatcher::AutoProcessEvent> ape;
|
||||
if (mIsMainThread == MAIN_THREAD) {
|
||||
DoMainThreadSpecificProcessing(reallyWait);
|
||||
ape.emplace();
|
||||
}
|
||||
|
||||
++mNestedEventLoopDepth;
|
||||
|
Loading…
Reference in New Issue
Block a user