зеркало из https://github.com/mozilla/pjs.git
Fix for bug 637099 (Remove JS_ClearScope calls on windows). r=mrbkap.
--HG-- extra : rebase_source : 8bdadc72a0b28c78e21758fab8f1035ee1dd9f3d
This commit is contained in:
Родитель
adea0e84cb
Коммит
8842d75d61
|
@ -1227,48 +1227,8 @@ nsGlobalWindow::ClearControllers()
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsGlobalWindow::TryClearWindowScope(nsISupports *aWindow)
|
||||
{
|
||||
nsGlobalWindow *window =
|
||||
static_cast<nsGlobalWindow *>(static_cast<nsIDOMWindow*>(aWindow));
|
||||
|
||||
// This termination function might be called when any script evaluation in our
|
||||
// context terminated, even if there are other scripts in the stack. Thus, we
|
||||
// have to check again if a script is executing and post a new termination
|
||||
// function if necessary.
|
||||
window->ClearScopeWhenAllScriptsStop();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::ClearScopeWhenAllScriptsStop()
|
||||
{
|
||||
NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
|
||||
|
||||
// We cannot clear scope safely until all the scripts in our script context
|
||||
// stopped. This might be a long wait, for example if one script is busy
|
||||
// because it started a nested event loop for a modal dialog.
|
||||
nsIScriptContext *jsscx = GetContextInternal();
|
||||
if (jsscx && jsscx->GetExecutingScript()) {
|
||||
// We ignore the return value because the only reason that we clear scope
|
||||
// here is to try to prevent leaks. Failing to clear scope might mean that
|
||||
// we'll leak more but if we don't have enough memory to allocate a
|
||||
// termination function we probably don't have to worry about this anyway.
|
||||
jsscx->SetTerminationFunction(TryClearWindowScope,
|
||||
static_cast<nsIDOMWindow *>(this));
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyWindowIDDestroyed("inner-window-destroyed");
|
||||
nsIScriptContext *scx = GetContextInternal();
|
||||
if (scx) {
|
||||
scx->ClearScope(mJSObject, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::FreeInnerObjects(bool aClearScope)
|
||||
nsGlobalWindow::FreeInnerObjects()
|
||||
{
|
||||
NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
|
||||
|
||||
|
@ -1330,9 +1290,7 @@ nsGlobalWindow::FreeInnerObjects(bool aClearScope)
|
|||
|
||||
mIndexedDB = nsnull;
|
||||
|
||||
if (aClearScope) {
|
||||
ClearScopeWhenAllScriptsStop();
|
||||
}
|
||||
NotifyWindowIDDestroyed("inner-window-destroyed");
|
||||
|
||||
if (mDummyJavaPluginOwner) {
|
||||
// Tear down the dummy java plugin.
|
||||
|
@ -1666,7 +1624,6 @@ nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
|
|||
// Great, we're the original document, check for one of the other
|
||||
// conditions.
|
||||
if (mDoc == aNewDocument) {
|
||||
// aClearScopeHint is false.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1840,10 +1797,8 @@ WindowStateHolder::~WindowStateHolder()
|
|||
// free it up.
|
||||
// Note that FreeInnerObjects may already have been called on the
|
||||
// inner window if its outer has already had SetDocShell(null)
|
||||
// called. In this case the contexts will all be null and the
|
||||
// true for aClearScope won't do anything; this is OK since
|
||||
// SetDocShell(null) already did it.
|
||||
mInnerWindow->FreeInnerObjects(true);
|
||||
// called.
|
||||
mInnerWindow->FreeInnerObjects();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2006,12 +1961,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
// Make sure to clear scope on the outer window *before* we
|
||||
// initialize the new inner window. If we don't, things
|
||||
// (Object.prototype etc) could leak from the old outer to the new
|
||||
// inner scope.
|
||||
mContext->ClearScope(mJSObject, false);
|
||||
|
||||
if (reUseInnerWindow) {
|
||||
// We're reusing the current inner window.
|
||||
NS_ASSERTION(!currentInner->IsFrozen(),
|
||||
|
@ -2081,8 +2030,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
}
|
||||
|
||||
if (currentInner && currentInner->mJSObject) {
|
||||
bool termFuncSet = false;
|
||||
|
||||
if (oldDoc == aDocument) {
|
||||
// Move the navigator from the old inner window to the new one since
|
||||
// this is a document.write. This is safe from a same-origin point of
|
||||
|
@ -2092,45 +2039,12 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
|||
if (newInnerWindow->mNavigator) {
|
||||
newInnerWindow->mNavigator->SetWindow(newInnerWindow);
|
||||
}
|
||||
|
||||
// Suspend the current context's request before Pop() resumes the old
|
||||
// context's request.
|
||||
JSAutoSuspendRequest asr(cx);
|
||||
|
||||
// Pop our context here so that we get the correct one for the
|
||||
// termination function.
|
||||
cxPusher.Pop();
|
||||
|
||||
JSContext *oldCx = nsContentUtils::GetCurrentJSContext();
|
||||
|
||||
nsIScriptContext *callerScx;
|
||||
if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) {
|
||||
// We're called from document.open() (and document.open() is
|
||||
// called from JS), clear the scope etc in a termination
|
||||
// function on the calling context to prevent clearing the
|
||||
// calling scope.
|
||||
NS_ASSERTION(!currentInner->IsFrozen(),
|
||||
"How does this opened window get into session history");
|
||||
|
||||
JSAutoRequest ar(oldCx);
|
||||
|
||||
callerScx->SetTerminationFunction(ClearWindowScope,
|
||||
static_cast<nsIDOMWindow *>
|
||||
(currentInner));
|
||||
|
||||
termFuncSet = true;
|
||||
}
|
||||
|
||||
// Re-push our context.
|
||||
cxPusher.Push(cx);
|
||||
}
|
||||
|
||||
// Don't clear scope on our current inner window if it's going to be
|
||||
// Don't free objects on our current inner window if it's going to be
|
||||
// held in the bfcache.
|
||||
if (!currentInner->IsFrozen()) {
|
||||
// Skip the ClearScope if we set a termination function to do
|
||||
// it ourselves, later.
|
||||
currentInner->FreeInnerObjects(!termFuncSet);
|
||||
currentInner->FreeInnerObjects();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2433,7 +2347,7 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
|
||||
NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
|
||||
"bad outer window pointer");
|
||||
inner->FreeInnerObjects(true);
|
||||
inner->FreeInnerObjects();
|
||||
}
|
||||
|
||||
// Make sure that this is called before we null out the document.
|
||||
|
@ -2455,10 +2369,6 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
mFocusedNode = nsnull;
|
||||
}
|
||||
|
||||
if (mContext) {
|
||||
mContext->ClearScope(mJSObject, true);
|
||||
}
|
||||
|
||||
ClearControllers();
|
||||
|
||||
mChromeEventHandler = nsnull; // force release now
|
||||
|
@ -8985,17 +8895,6 @@ nsGlobalWindow::CloseWindow(nsISupports *aWindow)
|
|||
// else if OOM, better not to close. That might cause a crash.
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
|
||||
{
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
|
||||
nsIScriptContext *scx = sgo->GetContext();
|
||||
if (scx) {
|
||||
scx->ClearScope(sgo->GetGlobalJSObject(), true);
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindow: Timeout Functions
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -595,11 +595,9 @@ protected:
|
|||
virtual ~nsGlobalWindow();
|
||||
void CleanUp(bool aIgnoreModalDialog);
|
||||
void ClearControllers();
|
||||
static void TryClearWindowScope(nsISupports* aWindow);
|
||||
void ClearScopeWhenAllScriptsStop();
|
||||
nsresult FinalClose();
|
||||
|
||||
void FreeInnerObjects(bool aClearScope);
|
||||
void FreeInnerObjects();
|
||||
nsGlobalWindow *CallerInnerWindow();
|
||||
|
||||
nsresult InnerSetNewDocument(nsIDocument* aDocument);
|
||||
|
@ -677,7 +675,6 @@ protected:
|
|||
nsIDOMWindow **aReturn);
|
||||
|
||||
static void CloseWindow(nsISupports* aWindow);
|
||||
static void ClearWindowScope(nsISupports* aWindow);
|
||||
|
||||
// Timeout Functions
|
||||
// Language agnostic timeout function (all args passed).
|
||||
|
|
|
@ -75,8 +75,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
|
|||
NS_ISCRIPTCONTEXTPRINCIPAL_IID)
|
||||
|
||||
#define NS_ISCRIPTCONTEXT_IID \
|
||||
{ 0xf3840057, 0x4fe5, 0x4f92, \
|
||||
{ 0xa3, 0xb8, 0x27, 0xd7, 0x44, 0x6f, 0x72, 0x4d } }
|
||||
{ 0x6d69fbee, 0x0723, 0x48f5, \
|
||||
{ 0x82, 0x48, 0xcd, 0xcf, 0x88, 0xac, 0x25, 0x74 } }
|
||||
|
||||
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
|
||||
know what language we have is a little silly... */
|
||||
|
@ -427,20 +427,6 @@ public:
|
|||
*/
|
||||
virtual nsresult InitClasses(JSObject* aGlobalObj) = 0;
|
||||
|
||||
/**
|
||||
* Clear the scope object - may be called either as we are being torn down,
|
||||
* or before we are attached to a different document.
|
||||
*
|
||||
* aClearFromProtoChain is probably somewhat JavaScript specific. It
|
||||
* indicates that the global scope polluter should be removed from the
|
||||
* prototype chain and that the objects in the prototype chain should
|
||||
* also have their scopes cleared. We don't do this all the time
|
||||
* because the prototype chain is shared between inner and outer
|
||||
* windows, and needs to stay with inner windows that we're keeping
|
||||
* around.
|
||||
*/
|
||||
virtual void ClearScope(void* aGlobalObj, bool aClearFromProtoChain) = 0;
|
||||
|
||||
/**
|
||||
* Tell the context we're about to be reinitialize it.
|
||||
*/
|
||||
|
|
|
@ -3015,82 +3015,6 @@ nsJSContext::InitClasses(JSObject* aGlobalObj)
|
|||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsJSContext::ClearScope(void *aGlobalObj, bool aClearFromProtoChain)
|
||||
{
|
||||
// Push our JSContext on our thread's context stack.
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
|
||||
if (stack && NS_FAILED(stack->Push(mContext))) {
|
||||
stack = nsnull;
|
||||
}
|
||||
|
||||
if (aGlobalObj) {
|
||||
JSObject *obj = (JSObject *)aGlobalObj;
|
||||
JSAutoRequest ar(mContext);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
ac.enterAndIgnoreErrors(mContext, obj);
|
||||
|
||||
// Grab a reference to the window property, which is the outer
|
||||
// window, so that we can re-define it once we've cleared
|
||||
// scope. This is what keeps the outer window alive in cases where
|
||||
// nothing else does.
|
||||
jsval window;
|
||||
if (!JS_GetProperty(mContext, obj, "window", &window)) {
|
||||
window = JSVAL_VOID;
|
||||
|
||||
JS_ClearPendingException(mContext);
|
||||
}
|
||||
|
||||
JS_ClearScope(mContext, obj);
|
||||
|
||||
NS_ABORT_IF_FALSE(!xpc::WrapperFactory::IsXrayWrapper(obj), "unexpected wrapper");
|
||||
|
||||
if (window != JSVAL_VOID) {
|
||||
if (!JS_DefineProperty(mContext, obj, "window", window,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY |
|
||||
JSPROP_PERMANENT)) {
|
||||
JS_ClearPendingException(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
if (!js::GetObjectParent(obj)) {
|
||||
JS_ClearRegExpStatics(mContext, obj);
|
||||
}
|
||||
|
||||
// Always clear watchpoints, to deal with two cases:
|
||||
// 1. The first document for this window is loading, and a miscreant has
|
||||
// preset watchpoints on the window object in order to attack the new
|
||||
// document's privileged information.
|
||||
// 2. A document loaded and used watchpoints on its own window, leaving
|
||||
// them set until the next document loads. We must clean up window
|
||||
// watchpoints here.
|
||||
// Watchpoints set on document and subordinate objects are all cleared
|
||||
// when those sub-window objects are finalized, after JS_ClearScope and
|
||||
// a GC run that finds them to be garbage.
|
||||
::JS_ClearWatchPointsForObject(mContext, obj);
|
||||
|
||||
// Since the prototype chain is shared between inner and outer (and
|
||||
// stays with the inner), we don't clear things from the prototype
|
||||
// chain when we're clearing an outer window whose current inner we
|
||||
// still want.
|
||||
if (aClearFromProtoChain) {
|
||||
nsWindowSH::InvalidateGlobalScopePolluter(mContext, obj);
|
||||
|
||||
// Clear up obj's prototype chain, but not Object.prototype.
|
||||
for (JSObject *o = ::JS_GetPrototype(obj), *next;
|
||||
o && (next = ::JS_GetPrototype(o)); o = next)
|
||||
::JS_ClearScope(mContext, o);
|
||||
}
|
||||
}
|
||||
|
||||
if (stack) {
|
||||
stack->Pop(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsJSContext::WillInitializeContext()
|
||||
{
|
||||
|
|
|
@ -161,7 +161,6 @@ public:
|
|||
virtual void SetGCOnDestruction(bool aGCOnDestruction);
|
||||
|
||||
virtual nsresult InitClasses(JSObject* aGlobalObj);
|
||||
virtual void ClearScope(void* aGlobalObj, bool bClearPolluters);
|
||||
|
||||
virtual void WillInitializeContext();
|
||||
virtual void DidInitializeContext();
|
||||
|
|
|
@ -156,6 +156,12 @@ _TEST_FILES = \
|
|||
test_bug698061.html \
|
||||
test_bug707749.html \
|
||||
test_bug691707.html \
|
||||
test_bug304459.html \
|
||||
iframe_bug304459-1.html \
|
||||
iframe_bug304459-2.html \
|
||||
test_bug38959.html \
|
||||
iframe_bug38959-1.html \
|
||||
iframe_bug38959-2.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Iframe test for bug 304459</title>
|
||||
</head>
|
||||
<body">
|
||||
<script>
|
||||
|
||||
Object.prototype.x = "oops";
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Iframe test for bug 304459</title>
|
||||
</head>
|
||||
<body">
|
||||
<script>
|
||||
|
||||
var result;
|
||||
try {
|
||||
x == undefined;
|
||||
} catch (e) {
|
||||
result = true;
|
||||
}
|
||||
window.parent.postMessage(result, "http://mochi.test:8888");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Iframe test for bug 38959</title>
|
||||
</head>
|
||||
<body">
|
||||
<script>
|
||||
|
||||
x = false;
|
||||
window.opener.postMessage(1, "http://mochi.test:8888");
|
||||
window.close();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Iframe test for bug 38959</title>
|
||||
</head>
|
||||
<body">
|
||||
<script>
|
||||
|
||||
x = true;
|
||||
window.opener.postMessage(2, "http://mochi.test:8888");
|
||||
window.close();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=304459
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 304459</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=304459">Mozilla Bug 304459</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe id="frame"></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 304459 **/
|
||||
|
||||
function iframeLoaded()
|
||||
{
|
||||
var frame = document.getElementById("frame");
|
||||
frame.onload = undefined;
|
||||
frame.src = "http://example.org/tests/dom/tests/mochitest/bugs/iframe_bug304459-2.html";
|
||||
}
|
||||
|
||||
function receiveMessage(evt)
|
||||
{
|
||||
ok(evt.data, "Prototype leaks across navigation");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
var frame = document.getElementById("frame");
|
||||
frame.onload = iframeLoaded;
|
||||
frame.src = "iframe_bug304459-1.html"
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=38959
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 38959</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=38959">Mozilla Bug 38959</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe id="frame"></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 38959 **/
|
||||
|
||||
var newValue;
|
||||
|
||||
function watcher(id, ol, ne)
|
||||
{
|
||||
newValue = ne;
|
||||
return ne;
|
||||
}
|
||||
|
||||
function openWindow(url, crossOrigin)
|
||||
{
|
||||
newValue = true;
|
||||
var w = window.open(url);
|
||||
w.watch("x", watcher);
|
||||
}
|
||||
|
||||
function receiveMessage(evt)
|
||||
{
|
||||
ok(newValue, "Watchpoints only allowed same-origin.");
|
||||
if (evt.data == 1) {
|
||||
openWindow("/tests/dom/tests/mochitest/bugs/iframe_bug38959-2.html");
|
||||
}
|
||||
else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
openWindow("http://example.org/tests/dom/tests/mochitest/bugs/iframe_bug38959-1.html");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче