Commit dbe2853e authored by Peter Van der Beken's avatar Peter Van der Beken
Browse files

Fix for bug 637116 (Leak documents+windows with replaceState, focus, event...

Fix for bug 637116 (Leak documents+windows with replaceState, focus, event handler closure). r=mrbkap.

--HG--
extra : rebase_source : 57090db5f6805d70811dc5753e2bc91feb65c0b5
parent 8f5ba7a3
Loading
Loading
Loading
Loading
+32 −22
Original line number Diff line number Diff line
@@ -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,6 +9559,9 @@ nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
    rv = aData->GetAsJSVal(&jsData);
    NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);

    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));
@@ -9571,15 +9575,16 @@ nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
        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 =
        // 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);
    }

    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!
    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 =
+2 −1
Original line number Diff line number Diff line
@@ -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.
+3 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
<!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>
+1 −0
Original line number Diff line number Diff line
@@ -25,3 +25,4 @@ asserts(1) load 504224.html # bug 564098
load 603531.html
load 601247.html
load 612018-1.html
load 637116.html
Loading