Bug 1311687 - Pop eval context on early returns. r=peterv
authorEric Rahm <erahm@mozilla.com>
Fri, 02 Dec 2016 10:33:48 -0800
changeset 325160 ccc5ede0fd337923f51a7ebe2bb1f6504d53fe61
parent 325159 b7738f546106aa38f9a7f1927c9211a77137979a
child 325161 d35117ca7509b057b8fc57e210f147617a13a493
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewerspeterv
bugs1311687
milestone53.0a1
Bug 1311687 - Pop eval context on early returns. r=peterv Make sure the eval context stack is cleaned up on failure. MozReview-Commit-ID: AUNen1xt9He
dom/xslt/xslt/txExecutionState.cpp
dom/xslt/xslt/txExecutionState.h
--- a/dom/xslt/xslt/txExecutionState.cpp
+++ b/dom/xslt/xslt/txExecutionState.cpp
@@ -154,17 +154,26 @@ txExecutionState::end(nsresult aResult)
         popTemplateRule();
     }
     else if (!mOutputHandler) {
         return NS_OK;
     }
     return mOutputHandler->endDocument(aResult);
 }
 
-
+void
+txExecutionState::popAndDeleteEvalContextUntil(txIEvalContext* aContext)
+{
+  auto ctx = popEvalContext();
+  while (ctx && ctx != aContext) {
+    MOZ_RELEASE_ASSERT(ctx != mInitialEvalContext);
+    delete ctx;
+    ctx = popEvalContext();
+  }
+}
 
 nsresult
 txExecutionState::getVariable(int32_t aNamespace, nsIAtom* aLName,
                               txAExprResult*& aResult)
 {
     nsresult rv = NS_OK;
     txExpandedName name(aNamespace, aLName);
 
@@ -222,43 +231,57 @@ txExecutionState::getVariable(int32_t aN
     // evaluate the global variable
     pushEvalContext(mInitialEvalContext);
     if (var->mExpr) {
         txVariableMap* oldVars = mLocalVariables;
         mLocalVariables = nullptr;
         rv = var->mExpr->evaluate(getEvalContext(), &aResult);
         mLocalVariables = oldVars;
 
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_FAILED(rv)) {
+          popAndDeleteEvalContextUntil(mInitialEvalContext);
+          return rv;
+        }
     }
     else {
         nsAutoPtr<txRtfHandler> rtfHandler(new txRtfHandler);
-        NS_ENSURE_TRUE(rtfHandler, NS_ERROR_OUT_OF_MEMORY);
 
         rv = pushResultHandler(rtfHandler);
-        NS_ENSURE_SUCCESS(rv, rv);
-        
+        if (NS_FAILED(rv)) {
+          popAndDeleteEvalContextUntil(mInitialEvalContext);
+          return rv;
+        }
+
         rtfHandler.forget();
 
         txInstruction* prevInstr = mNextInstruction;
         // set return to nullptr to stop execution
         mNextInstruction = nullptr;
         rv = runTemplate(var->mFirstInstruction);
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_FAILED(rv)) {
+          popAndDeleteEvalContextUntil(mInitialEvalContext);
+          return rv;
+        }
 
         pushTemplateRule(nullptr, txExpandedName(), nullptr);
         rv = txXSLTProcessor::execute(*this);
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_FAILED(rv)) {
+          popAndDeleteEvalContextUntil(mInitialEvalContext);
+          return rv;
+        }
 
         popTemplateRule();
 
         mNextInstruction = prevInstr;
         rtfHandler = (txRtfHandler*)popResultHandler();
         rv = rtfHandler->getAsRTF(&aResult);
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_FAILED(rv)) {
+          popAndDeleteEvalContextUntil(mInitialEvalContext);
+          return rv;
+        }
     }
     popEvalContext();
 
     // Remove the placeholder and insert the calculated value
     mGlobalVariableValues.removeVariable(name);
     rv = mGlobalVariableValues.bindVariable(name, aResult);
     if (NS_FAILED(rv)) {
         NS_RELEASE(aResult);
--- a/dom/xslt/xslt/txExecutionState.h
+++ b/dom/xslt/xslt/txExecutionState.h
@@ -89,16 +89,24 @@ public:
         int32_t mModeNsId;
         nsCOMPtr<nsIAtom> mModeLocalName;
         txVariableMap* mParams;
     };
 
     // Stack functions
     nsresult pushEvalContext(txIEvalContext* aContext);
     txIEvalContext* popEvalContext();
+
+    /**
+     * Helper that deletes all entries before |aContext| and then
+     * pops it off the stack. The caller must delete |aContext| if
+     * desired.
+     */
+    void popAndDeleteEvalContextUntil(txIEvalContext* aContext);
+
     nsresult pushBool(bool aBool);
     bool popBool();
     nsresult pushResultHandler(txAXMLEventHandler* aHandler);
     txAXMLEventHandler* popResultHandler();
     void pushTemplateRule(txStylesheet::ImportFrame* aFrame,
                           const txExpandedName& aMode,
                           txVariableMap* aParams);
     void popTemplateRule();