mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Fix for bug 637116 (Leak documents+windows with replaceState, focus, event handler closure). r=mrbkap.
--HG-- extra : rebase_source : 57090db5f6805d70811dc5753e2bc91feb65c0b5
This commit is contained in:
parent
8f5ba7a3c0
commit
dbe2853e3d
@ -9547,7 +9547,8 @@ nsDocShell::SetReferrerURI(nsIURI * aURI)
|
||||
//*****************************************************************************
|
||||
|
||||
nsresult
|
||||
nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
|
||||
nsDocShell::StringifyJSValVariant(JSContext *aCx, nsIVariant *aData,
|
||||
nsAString &aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
aResult.Truncate();
|
||||
@ -9558,28 +9559,32 @@ nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
|
||||
rv = aData->GetAsJSVal(&jsData);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Now get the JSContext associated with the current document.
|
||||
// First get the current document.
|
||||
nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
|
||||
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIJSContextStack> contextStack;
|
||||
JSContext *cx = aCx;
|
||||
if (!cx) {
|
||||
// Now get the JSContext associated with the current document.
|
||||
// First get the current document.
|
||||
nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
|
||||
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
|
||||
|
||||
// Get the JSContext from the document, like we do in
|
||||
// nsContentUtils::GetContextFromDocument().
|
||||
nsIScriptGlobalObject *sgo = document->GetScopeObject();
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
|
||||
// Get the JSContext from the document, like we do in
|
||||
// nsContentUtils::GetContextFromDocument().
|
||||
nsIScriptGlobalObject *sgo = document->GetScopeObject();
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
|
||||
|
||||
nsIScriptContext *scx = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
|
||||
nsIScriptContext *scx = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
|
||||
|
||||
JSContext *cx = (JSContext *)scx->GetNativeContext();
|
||||
cx = (JSContext *)scx->GetNativeContext();
|
||||
|
||||
// If our json call triggers a JS-to-C++ call, we want that call to use cx
|
||||
// as the context. So we push cx onto the context stack.
|
||||
nsCOMPtr<nsIJSContextStack> contextStack =
|
||||
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// If our json call triggers a JS-to-C++ call, we want that call to use
|
||||
// aCx as the context. So we push aCx onto the context stack.
|
||||
contextStack =
|
||||
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
contextStack->Push(cx);
|
||||
contextStack->Push(cx);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
|
||||
if(json) {
|
||||
@ -9590,15 +9595,20 @@ nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Always pop the stack!
|
||||
contextStack->Pop(&cx);
|
||||
if (contextStack) {
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
|
||||
contextStack->Pop(&cx);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
|
||||
const nsAString& aURL, PRBool aReplace)
|
||||
const nsAString& aURL, PRBool aReplace, JSContext* aCx)
|
||||
{
|
||||
// Implements History.pushState and History.replaceState
|
||||
|
||||
@ -9651,7 +9661,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
|
||||
|
||||
rv = StringifyJSValVariant(aData, dataStr);
|
||||
rv = StringifyJSValVariant(aCx, aData, dataStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDocument> newDocument =
|
||||
|
@ -338,7 +338,8 @@ protected:
|
||||
|
||||
// Tries to stringify a given variant by converting it to JSON. This only
|
||||
// works if the variant is backed by a JSVal.
|
||||
nsresult StringifyJSValVariant(nsIVariant *aData, nsAString &aResult);
|
||||
nsresult StringifyJSValVariant(JSContext *aCx, nsIVariant *aData,
|
||||
nsAString &aResult);
|
||||
|
||||
// Returns PR_TRUE if would have called FireOnLocationChange,
|
||||
// but did not because aFireOnLocationChange was false on entry.
|
||||
|
@ -43,6 +43,7 @@
|
||||
%{ C++
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
struct JSContext;
|
||||
%}
|
||||
|
||||
/**
|
||||
@ -71,7 +72,7 @@ interface nsIPrincipal;
|
||||
interface nsIWebBrowserPrint;
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(1917a6d6-31f6-4033-868d-f15ca08ca2df)]
|
||||
[scriptable, uuid(f77271a1-0b22-4581-af6d-529125f1901d)]
|
||||
interface nsIDocShell : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -174,6 +175,7 @@ interface nsIDocShell : nsISupports
|
||||
* Do either a history.pushState() or history.replaceState() operation,
|
||||
* depending on the value of aReplace.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void addState(in nsIVariant aData, in DOMString aTitle,
|
||||
in DOMString aURL, in boolean aReplace);
|
||||
|
||||
|
29
dom/base/crashtests/637116.html
Normal file
29
dom/base/crashtests/637116.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function K(v) { return function() { return v; } }
|
||||
|
||||
var errorProxy = Proxy.create({get: function() { throw new Error(); }});
|
||||
|
||||
function boom()
|
||||
{
|
||||
var focused = document.createElementNS("http://www.w3.org/1999/xhtml", "input");
|
||||
document.body.appendChild(focused);
|
||||
var otherWin = window.open("data:text/html,1", "_blank", "width=200,height=200");
|
||||
try { otherWin.history.replaceState(errorProxy, "title", "replaceState.html"); } catch(e) {}
|
||||
focused.focus();
|
||||
focused.addEventListener("foo", K(otherWin.applicationCache), false);
|
||||
otherWin.close();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
<button onclick="boom();">If you have popups blocked, click here to start the leak test</button>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -25,3 +25,4 @@ asserts(1) load 504224.html # bug 564098
|
||||
load 603531.html
|
||||
load 601247.html
|
||||
load 612018-1.html
|
||||
load 637116.html
|
||||
|
@ -284,7 +284,7 @@ nsHistory::Go(PRInt32 aDelta)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
|
||||
const nsAString& aURL)
|
||||
const nsAString& aURL, JSContext* aCx)
|
||||
{
|
||||
// Check that PushState hasn't been pref'ed off.
|
||||
if (!nsContentUtils::GetBoolPref(sAllowPushStatePrefStr, PR_FALSE))
|
||||
@ -305,7 +305,7 @@ nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
|
||||
|
||||
// PR_FALSE tells the docshell to add a new history entry instead of
|
||||
// modifying the current one.
|
||||
nsresult rv = docShell->AddState(aData, aTitle, aURL, PR_FALSE);
|
||||
nsresult rv = docShell->AddState(aData, aTitle, aURL, PR_FALSE, aCx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@ -313,7 +313,7 @@ nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHistory::ReplaceState(nsIVariant *aData, const nsAString& aTitle,
|
||||
const nsAString& aURL)
|
||||
const nsAString& aURL, JSContext* aCx)
|
||||
{
|
||||
// Check that ReplaceState hasn't been pref'ed off
|
||||
if (!nsContentUtils::GetBoolPref(sAllowReplaceStatePrefStr, PR_FALSE))
|
||||
@ -334,7 +334,7 @@ nsHistory::ReplaceState(nsIVariant *aData, const nsAString& aTitle,
|
||||
|
||||
// PR_TRUE tells the docshell to modify the current SHEntry, rather than
|
||||
// create a new one.
|
||||
return docShell->AddState(aData, aTitle, aURL, PR_TRUE);
|
||||
return docShell->AddState(aData, aTitle, aURL, PR_TRUE, aCx);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -39,9 +39,13 @@
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
%{ C++
|
||||
struct JSContext;
|
||||
%}
|
||||
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(dba2e0d5-1682-40a3-be46-28eda99d757e)]
|
||||
[scriptable, uuid(d5a3006b-dd6b-4ba3-81be-6559f8889e60)]
|
||||
interface nsIDOMHistory : nsISupports
|
||||
{
|
||||
readonly attribute long length;
|
||||
@ -54,9 +58,11 @@ interface nsIDOMHistory : nsISupports
|
||||
|
||||
void go([optional] in long aDelta);
|
||||
DOMString item(in unsigned long index);
|
||||
[implicit_jscontext]
|
||||
void pushState(in nsIVariant aData,
|
||||
in DOMString aTitle,
|
||||
[optional] in DOMString aURL);
|
||||
[implicit_jscontext]
|
||||
void replaceState(in nsIVariant aData,
|
||||
in DOMString aTitle,
|
||||
[optional] in DOMString aURL);
|
||||
|
Loading…
Reference in New Issue
Block a user