Issue #2452 - Prevent nsDocShell access when it is already being destroyed

https://bugzilla.mozilla.org/show_bug.cgi?id=1432396
This commit is contained in:
Martok
2024-01-14 22:31:26 +01:00
committed by roytam1
parent a9d7255ba1
commit 2a533c943d
3 changed files with 76 additions and 9 deletions
+65 -8
View File
@@ -893,6 +893,8 @@ nsDocShell::~nsDocShell()
nsresult
nsDocShell::Init()
{
MOZ_ASSERT(!mIsBeingDestroyed);
nsresult rv = nsDocLoader::Init();
NS_ENSURE_SUCCESS(rv, rv);
@@ -1921,6 +1923,8 @@ bool
nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
bool aFireOnLocationChange, uint32_t aLocationFlags)
{
MOZ_ASSERT(!mIsBeingDestroyed);
if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n",
this, aURI ? aURI->GetSpecOrDefault().get() : "");
@@ -2181,6 +2185,8 @@ nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
NS_IMETHODIMP
nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
{
MOZ_ASSERT(!mIsBeingDestroyed);
bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
if (changed) {
mPrivateBrowsingId = aUsePrivateBrowsing ? 1 : 0;
@@ -2251,6 +2257,8 @@ nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
NS_IMETHODIMP
nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
{
MOZ_ASSERT(!mIsBeingDestroyed);
bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
if (change && UsePrivateBrowsing()) {
AssertOriginAttributesMatchPrivateBrowsing();
@@ -2753,6 +2761,8 @@ nsDocShell::GetSecurityUI(nsISecureBrowserUI** aSecurityUI)
NS_IMETHODIMP
nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI)
{
MOZ_ASSERT(!mIsBeingDestroyed);
mSecurityUI = aSecurityUI;
mSecurityUI->SetDocShell(this);
return NS_OK;
@@ -3935,6 +3945,10 @@ PrintDocTree(nsIDocShellTreeItem* aParentNode)
NS_IMETHODIMP
nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
{
if (mIsBeingDestroyed && aTreeOwner) {
return NS_ERROR_FAILURE;
}
#ifdef DEBUG_DOCSHELL_FOCUS
nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
if (item) {
@@ -5216,6 +5230,8 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
const char* aCSSClass,
nsIChannel* aFailedChannel)
{
MOZ_ASSERT(!mIsBeingDestroyed);
#if defined(DEBUG)
if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
nsAutoCString chanName;
@@ -5571,6 +5587,8 @@ nsDocShell::SetSessionHistory(nsISHistory* aSessionHistory)
// make sure that we are the root docshell and
// set a handle to root docshell in SH.
MOZ_ASSERT(!mIsBeingDestroyed);
nsCOMPtr<nsIDocShellTreeItem> root;
/* Get the root docshell. If *this* is the root docshell
* then save a handle to *this* in SH. SH needs it to do
@@ -5751,16 +5769,22 @@ nsDocShell::Create()
NS_IMETHODIMP
nsDocShell::Destroy()
{
// XXX: We allow this function to be called just once. If you are going to
// reset new variables in this function, please make sure the variables will
// never be re-initialized. Adding assertions to check |mIsBeingDestroyed|
// in the setter functions for the variables would be enough.
if (mIsBeingDestroyed) {
return NS_ERROR_DOCSHELL_DYING;
}
NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
"Unexpected item type in docshell");
if (!mIsBeingDestroyed) {
nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
if (serv) {
const char* msg = mItemType == typeContent ?
NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
}
nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
if (serv) {
const char* msg = mItemType == typeContent ?
NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
}
mIsBeingDestroyed = true;
@@ -6043,6 +6067,7 @@ nsDocShell::GetParentWidget(nsIWidget** aParentWidget)
NS_IMETHODIMP
nsDocShell::SetParentWidget(nsIWidget* aParentWidget)
{
MOZ_ASSERT(!mIsBeingDestroyed);
mParentWidget = aParentWidget;
return NS_OK;
@@ -6313,6 +6338,8 @@ nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
return NS_OK;
}
MOZ_ASSERT(!mIsBeingDestroyed);
mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
NS_ASSERTION(mOnePermittedSandboxedNavigator,
"One Permitted Sandboxed Navigator must support weak references.");
@@ -6673,6 +6700,8 @@ nsDocShell::RefreshURI(nsIURI* aURI,
bool aMetaRefresh,
nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(!mIsBeingDestroyed);
NS_ENSURE_ARG(aURI);
/* Check if Meta refresh/redirects are permitted. Some
@@ -8056,6 +8085,10 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
// wrong information :-(
//
(void)FirePageHideNotification(!mSavingOldViewer);
// pagehide notification might destroy this docshell.
if (mIsBeingDestroyed) {
return NS_ERROR_DOCSHELL_DYING;
}
}
// Now make sure we don't think we're in the middle of firing unload after
@@ -8199,6 +8232,8 @@ nsDocShell::CanSavePresentation(uint32_t aLoadType,
void
nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry)
{
MOZ_ASSERT(!mIsBeingDestroyed);
NS_ASSERTION(!mEditorData,
"Why reattach an editor when we already have one?");
NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
@@ -8236,6 +8271,9 @@ nsDocShell::DetachEditorFromWindow()
if (NS_SUCCEEDED(res)) {
// Make mOSHE hold the owning ref to the editor data.
if (mOSHE) {
MOZ_ASSERT(!mIsBeingDestroyed || !mOSHE->HasDetachedEditor(),
"We should not set the editor data again once after we "
"detached the editor data during destroying this docshell");
mOSHE->SetEditorData(mEditorData.forget());
} else {
mEditorData = nullptr;
@@ -8422,6 +8460,8 @@ nsDocShell::GetRestoringDocument(bool* aRestoring)
nsresult
nsDocShell::RestorePresentation(nsISHEntry* aSHEntry, bool* aRestoring)
{
MOZ_ASSERT(!mIsBeingDestroyed);
NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
"RestorePresentation should only be called for history loads");
@@ -8583,6 +8623,10 @@ nsDocShell::RestoreFromHistory()
// Notify the old content viewer that it's being hidden.
FirePageHideNotification(!mSavingOldViewer);
// pagehide notification might destroy this docshell.
if (mIsBeingDestroyed) {
return NS_ERROR_DOCSHELL_DYING;
}
// If mLSHE was changed as a result of the pagehide event, then
// something else was loaded. Don't finish restoring.
@@ -9040,7 +9084,7 @@ nsDocShell::CreateContentViewer(const nsACString& aContentType,
{
*aContentHandler = nullptr;
if (!mTreeOwner) {
if (!mTreeOwner || mIsBeingDestroyed) {
// If we don't have a tree owner, then we're in the process of being
// destroyed. Rather than continue trying to load something, just give up.
return NS_ERROR_DOCSHELL_DYING;
@@ -9085,6 +9129,11 @@ nsDocShell::CreateContentViewer(const nsACString& aContentType,
aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
}
FirePageHideNotification(!mSavingOldViewer);
if (mIsBeingDestroyed) {
// Force to stop the newly created orphaned viewer.
viewer->Stop();
return NS_ERROR_DOCSHELL_DYING;
}
mLoadingURI = nullptr;
// Set mFiredUnloadEvent = false so that the unload handler for the
@@ -9274,6 +9323,8 @@ nsDocShell::NewContentViewerObj(const nsACString& aContentType,
nsresult
nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer)
{
MOZ_ASSERT(!mIsBeingDestroyed);
//
// Copy content viewer state from previous or parent content viewer.
//
@@ -13466,6 +13517,8 @@ nsDocShell::EnsureScriptEnvironment()
NS_IMETHODIMP
nsDocShell::EnsureEditorData()
{
MOZ_ASSERT(!mIsBeingDestroyed);
bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
// We shouldn't recreate the editor data if it already exists, or
@@ -13481,6 +13534,8 @@ nsDocShell::EnsureEditorData()
nsresult
nsDocShell::EnsureTransferableHookData()
{
MOZ_ASSERT(!mIsBeingDestroyed);
if (!mTransferableHookData) {
mTransferableHookData = new nsTransferableHookData();
}
@@ -14568,6 +14623,8 @@ nsDocShell::CanSetOriginAttributes()
nsresult
nsDocShell::SetOriginAttributes(const DocShellOriginAttributes& aAttrs)
{
MOZ_ASSERT(!mIsBeingDestroyed);
if (!CanSetOriginAttributes()) {
return NS_ERROR_FAILURE;
}