зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset b1fe3750580d (bug 1471989) for build bustages on a CLOSED TREE
This commit is contained in:
Родитель
017a925896
Коммит
f9260c6914
|
@ -109,9 +109,6 @@ WindowDestroyedEvent::Run() {
|
|||
JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
|
||||
if (obj && !js::IsSystemRealm(js::GetNonCCWObjectRealm(obj))) {
|
||||
JS::Realm* realm = js::GetNonCCWObjectRealm(obj);
|
||||
|
||||
xpc::NukeJSStackFrames(realm);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> pc =
|
||||
nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "js/TypeDecls.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/SavedFrameAPI.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
|
@ -198,7 +197,7 @@ already_AddRefed<nsIStackFrame> GetCurrentJSStack(int32_t aMaxDepth) {
|
|||
|
||||
namespace exceptions {
|
||||
|
||||
class JSStackFrame final : public nsIStackFrame, public xpc::JSStackFrameBase {
|
||||
class JSStackFrame : public nsIStackFrame {
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSStackFrame)
|
||||
|
@ -210,12 +209,6 @@ class JSStackFrame final : public nsIStackFrame, public xpc::JSStackFrameBase {
|
|||
private:
|
||||
virtual ~JSStackFrame();
|
||||
|
||||
void Clear() override { mStack = nullptr; }
|
||||
|
||||
// Remove this frame from the per-realm list of live frames,
|
||||
// and clear out the stack pointer.
|
||||
void UnregisterAndClear();
|
||||
|
||||
JS::Heap<JSObject*> mStack;
|
||||
nsString mFormattedStack;
|
||||
|
||||
|
@ -253,29 +246,15 @@ JSStackFrame::JSStackFrame(JS::Handle<JSObject*> aStack)
|
|||
MOZ_ASSERT(JS::IsUnwrappedSavedFrame(mStack));
|
||||
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
xpc::RegisterJSStackFrame(js::GetNonCCWObjectRealm(aStack), this);
|
||||
}
|
||||
|
||||
JSStackFrame::~JSStackFrame() {
|
||||
UnregisterAndClear();
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
void JSStackFrame::UnregisterAndClear() {
|
||||
if (!mStack) {
|
||||
return;
|
||||
}
|
||||
|
||||
xpc::UnregisterJSStackFrame(js::GetNonCCWObjectRealm(mStack), this);
|
||||
Clear();
|
||||
}
|
||||
JSStackFrame::~JSStackFrame() { mozilla::DropJSObjects(this); }
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(JSStackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(JSStackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCaller)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAsyncCaller)
|
||||
tmp->UnregisterAndClear();
|
||||
tmp->mStack = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(JSStackFrame)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCaller)
|
||||
|
|
|
@ -382,51 +382,6 @@ static bool PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void RealmPrivate::RegisterStackFrame(JSStackFrameBase* aFrame) {
|
||||
mJSStackFrames.PutEntry(aFrame);
|
||||
}
|
||||
|
||||
void RealmPrivate::UnregisterStackFrame(JSStackFrameBase* aFrame) {
|
||||
mJSStackFrames.RemoveEntry(aFrame);
|
||||
}
|
||||
|
||||
void RealmPrivate::NukeJSStackFrames() {
|
||||
for (auto iter = mJSStackFrames.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Get()->GetKey()->Clear();
|
||||
}
|
||||
|
||||
mJSStackFrames.Clear();
|
||||
}
|
||||
|
||||
void xpc::RegisterJSStackFrame(JS::Realm* aRealm,
|
||||
JSStackFrameBase* aStackFrame) {
|
||||
RealmPrivate* realmPrivate = RealmPrivate::Get(aRealm);
|
||||
if (!realmPrivate) {
|
||||
return;
|
||||
}
|
||||
|
||||
realmPrivate->RegisterStackFrame(aStackFrame);
|
||||
}
|
||||
|
||||
void xpc::UnregisterJSStackFrame(JS::Realm* aRealm,
|
||||
JSStackFrameBase* aStackFrame) {
|
||||
RealmPrivate* realmPrivate = RealmPrivate::Get(aRealm);
|
||||
if (!realmPrivate) {
|
||||
return;
|
||||
}
|
||||
|
||||
realmPrivate->UnregisterStackFrame(aStackFrame);
|
||||
}
|
||||
|
||||
void xpc::NukeJSStackFrames(JS::Realm* aRealm) {
|
||||
RealmPrivate* realmPrivate = RealmPrivate::Get(aRealm);
|
||||
if (!realmPrivate) {
|
||||
return;
|
||||
}
|
||||
|
||||
realmPrivate->NukeJSStackFrames();
|
||||
}
|
||||
|
||||
Scriptability::Scriptability(JS::Realm* realm)
|
||||
: mScriptBlocks(0),
|
||||
mDocShellAllowsScript(true),
|
||||
|
|
|
@ -2915,19 +2915,11 @@ class RealmPrivate {
|
|||
locationURI = aLocationURI;
|
||||
}
|
||||
|
||||
// JSStackFrames are tracked on a per-realm basis so they
|
||||
// can be cleared when the associated window goes away.
|
||||
void RegisterStackFrame(JSStackFrameBase* aFrame);
|
||||
void UnregisterStackFrame(JSStackFrameBase* aFrame);
|
||||
void NukeJSStackFrames();
|
||||
|
||||
private:
|
||||
nsCString location;
|
||||
nsCOMPtr<nsIURI> locationURI;
|
||||
|
||||
bool TryParseLocationURI(LocationHint aType, nsIURI** aURI);
|
||||
|
||||
nsTHashtable<nsPtrHashKey<JSStackFrameBase>> mJSStackFrames;
|
||||
};
|
||||
|
||||
inline XPCWrappedNativeScope* ObjectScope(JSObject* obj) {
|
||||
|
|
|
@ -714,15 +714,6 @@ bool IfaceID2JSValue(JSContext* aCx, const nsXPTInterfaceInfo& aInfo,
|
|||
bool ContractID2JSValue(JSContext* aCx, JSString* aContract,
|
||||
JS::MutableHandleValue aVal);
|
||||
|
||||
class JSStackFrameBase {
|
||||
public:
|
||||
virtual void Clear() = 0;
|
||||
};
|
||||
|
||||
void RegisterJSStackFrame(JS::Realm* aRealm, JSStackFrameBase* aStackFrame);
|
||||
void UnregisterJSStackFrame(JS::Realm* aRealm, JSStackFrameBase* aStackFrame);
|
||||
void NukeJSStackFrames(JS::Realm* aRealm);
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
browser_consoleStack.html
|
||||
browser_deadObjectOnUnload.html
|
||||
[browser_dead_object.js]
|
||||
[browser_exception_leak.js]
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test page for https://bugzilla.mozilla.org/show_bug.cgi?id=1471989
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test page for Bug 1471989</title>
|
||||
</head>
|
||||
<body onUnload="onUnload();">
|
||||
<p><span id="samplepage">sample page</span></p>
|
||||
<script type="application/javascript">
|
||||
// Get something sent to ConsoleStorageAPI that has a stack.
|
||||
console.trace("whatever");
|
||||
|
||||
function onUnload() {
|
||||
console.log('in unload');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,52 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// For bug 1471989, test that an exception saved by chrome code can't leak the page.
|
||||
|
||||
add_task(async function test() {
|
||||
const url = "http://mochi.test:8888/browser/js/xpconnect/tests/browser/browser_consoleStack.html";
|
||||
let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let innerWindowId = browser.innerWindowID;
|
||||
|
||||
let stackTraceEmpty = await ContentTask.spawn(browser, {innerWindowId}, async function(args) {
|
||||
let {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm", {});
|
||||
let {Assert} = ChromeUtils.import("resource://testing-common/Assert.jsm", {});
|
||||
|
||||
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage);
|
||||
let consoleEvents = ConsoleAPIStorage.getEvents(args.innerWindowId);
|
||||
Assert.equal(consoleEvents.length, 1, "Should only be one console event for the window");
|
||||
|
||||
// Intentionally hold a reference to the console event.
|
||||
let leakedConsoleEvent = consoleEvents[0];
|
||||
|
||||
let doc = content.document;
|
||||
let promise = TestUtils.topicObserved("inner-window-nuked", (subject, data) => {
|
||||
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
return id == args.innerWindowId;
|
||||
});
|
||||
content.location = "http://example.org/";
|
||||
await promise;
|
||||
|
||||
// This string should be empty. For that to happen, two things
|
||||
// need to be true:
|
||||
//
|
||||
// a) ConsoleCallData::mStack is not null. This means that the
|
||||
// stack trace was not reified before the page was nuked. If it
|
||||
// was, then the correct |filename| value would be stored on the
|
||||
// object. (This is not a problem, except that it stops us from
|
||||
// testing the next condition.)
|
||||
//
|
||||
// b) ConsoleData::mStack.mStack is null. This means that the
|
||||
// JSStackFrame is keeping alive the JS object in the page after
|
||||
// the page was nuked, which leaks the page.
|
||||
return leakedConsoleEvent.stacktrace[0].filename;
|
||||
});
|
||||
|
||||
is(stackTraceEmpty, "",
|
||||
"JSStackFrame shouldn't leak mStack after window nuking");
|
||||
|
||||
BrowserTestUtils.removeTab(newTab);
|
||||
});
|
Загрузка…
Ссылка в новой задаче