bug702466 - Validate stack usage in xslt compiler r=sicking, a=dveditz
authorJohn Schoenick <john@pointysoftware.net>
Fri, 27 Jan 2012 23:00:07 -0800
changeset 35254 4e2214da4a826a1e0282409e9c829b3cade777f4
parent 35251 0219ac257e3c3f656fb7680db9c1d8af59197efc
child 35255 45b10d6e1176fba5adae73c52448b170d532b8a9
push id2016
push userdveditz@mozilla.com
push dateSun, 29 Jan 2012 00:37:51 +0000
reviewerssicking, dveditz
bugs702466
milestone1.9.2.27pre
bug702466 - Validate stack usage in xslt compiler r=sicking, a=dveditz
content/xslt/src/xslt/txStylesheetCompileHandlers.cpp
content/xslt/src/xslt/txStylesheetCompiler.cpp
content/xslt/src/xslt/txStylesheetCompiler.h
--- a/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp
+++ b/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp
@@ -1198,17 +1198,17 @@ txFnStartTopVariable(PRInt32 aNamespaceI
                      aState, select);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txVariableItem> var(
         new txVariableItem(name, select, aLocalName == txXSLTAtoms::param));
     NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
 
     aState.openInstructionContainer(var);
-    rv = aState.pushPtr(var);
+    rv = aState.pushPtr(var, aState.eVariableItem);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (var->mValue) {
         // XXX should be gTxErrorHandler?
         rv = aState.pushHandlerTable(gTxIgnoreHandler);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
@@ -1224,17 +1224,18 @@ txFnStartTopVariable(PRInt32 aNamespaceI
     return NS_OK;
 }
 
 nsresult
 txFnEndTopVariable(txStylesheetCompilerState& aState)
 {
     txHandlerTable* prev = aState.mHandlerTable;
     aState.popHandlerTable();
-    txVariableItem* var = static_cast<txVariableItem*>(aState.popPtr());
+    txVariableItem* var =
+        static_cast<txVariableItem*>(aState.popPtr(aState.eVariableItem));
 
     if (prev == gTxTopVariableHandler) {
         // No children were found.
         NS_ASSERTION(!var->mValue,
                      "There shouldn't be a select-expression here");
         var->mValue = new txLiteralExpr(EmptyString());
         NS_ENSURE_TRUE(var->mValue, NS_ERROR_OUT_OF_MEMORY);
     }
@@ -1726,17 +1727,17 @@ txFnStartCopy(PRInt32 aNamespaceID,
               nsIAtom* aPrefix,
               txStylesheetAttr* aAttributes,
               PRInt32 aAttrCount,
               txStylesheetCompilerState& aState)
 {
     nsAutoPtr<txCopy> copy(new txCopy);
     NS_ENSURE_TRUE(copy, NS_ERROR_OUT_OF_MEMORY);
 
-    nsresult rv = aState.pushPtr(copy);
+    nsresult rv = aState.pushPtr(copy, aState.eCopy);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(copy.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = parseUseAttrSets(aAttributes, aAttrCount, PR_FALSE, aState);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1748,17 +1749,17 @@ nsresult
 txFnEndCopy(txStylesheetCompilerState& aState)
 {
     nsAutoPtr<txInstruction> instr(new txEndElement);
     NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY);
 
     nsresult rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    txCopy* copy = static_cast<txCopy*>(aState.popPtr());
+    txCopy* copy = static_cast<txCopy*>(aState.popPtr(aState.eCopy));
     rv = aState.addGotoTarget(&copy->mBailTarget);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
 }
 
 /*
   xsl:copy-of
@@ -1899,54 +1900,54 @@ txFnStartForEach(PRInt32 aNamespaceID,
     nsAutoPtr<Expr> select;
     rv = getExprAttr(aAttributes, aAttrCount, txXSLTAtoms::select, PR_TRUE,
                      aState, select);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txPushNewContext> pushcontext(new txPushNewContext(select));
     NS_ENSURE_TRUE(pushcontext, NS_ERROR_OUT_OF_MEMORY);
 
-    rv = aState.pushPtr(pushcontext);
+    rv = aState.pushPtr(pushcontext, aState.ePushNewContext);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aState.pushSorter(pushcontext);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(pushcontext.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
     
     instr = new txPushNullTemplateRule;
     NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY);
 
-    rv = aState.pushPtr(instr);
+    rv = aState.pushPtr(instr, aState.ePushNullTemplateRule);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return aState.pushHandlerTable(gTxForEachHandler);
 }
 
 nsresult
 txFnEndForEach(txStylesheetCompilerState& aState)
 {
     aState.popHandlerTable();
 
     // This is a txPushNullTemplateRule
     txInstruction* pnullrule =
-        static_cast<txInstruction*>(aState.popPtr());
+        static_cast<txInstruction*>(aState.popPtr(aState.ePushNullTemplateRule));
 
     nsAutoPtr<txInstruction> instr(new txLoopNodeSet(pnullrule));
     nsresult rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     aState.popSorter();
     txPushNewContext* pushcontext =
-        static_cast<txPushNewContext*>(aState.popPtr());
+        static_cast<txPushNewContext*>(aState.popPtr(aState.ePushNewContext));
     aState.addGotoTarget(&pushcontext->mBailTarget);
 
     return NS_OK;
 }
 
 nsresult
 txFnStartElementContinueTemplate(PRInt32 aNamespaceID,
                                 nsIAtom* aLocalName,
@@ -1991,31 +1992,31 @@ txFnStartIf(PRInt32 aNamespaceID,
     nsAutoPtr<Expr> test;
     rv = getExprAttr(aAttributes, aAttrCount, txXSLTAtoms::test, PR_TRUE,
                      aState, test);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txConditionalGoto> condGoto(new txConditionalGoto(test, nsnull));
     NS_ENSURE_TRUE(condGoto, NS_ERROR_OUT_OF_MEMORY);
 
-    rv = aState.pushPtr(condGoto);
+    rv = aState.pushPtr(condGoto, aState.eConditionalGoto);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(condGoto.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
 }
 
 nsresult
 txFnEndIf(txStylesheetCompilerState& aState)
 {
     txConditionalGoto* condGoto =
-        static_cast<txConditionalGoto*>(aState.popPtr());
+        static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
     return aState.addGotoTarget(&condGoto->mTarget);
 }
 
 /*
   xsl:message
 
   txPushStringHandler
   [children]
@@ -2198,17 +2199,17 @@ txFnStartParam(PRInt32 aNamespaceID,
     txExpandedName name;
     rv = getQNameAttr(aAttributes, aAttrCount, txXSLTAtoms::name, PR_TRUE,
                       aState, name);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txCheckParam> checkParam(new txCheckParam(name));
     NS_ENSURE_SUCCESS(rv, rv);
     
-    rv = aState.pushPtr(checkParam);
+    rv = aState.pushPtr(checkParam, aState.eCheckParam);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(checkParam.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<Expr> select;
     rv = getExprAttr(aAttributes, aAttrCount, txXSLTAtoms::select, PR_FALSE,
@@ -2254,17 +2255,18 @@ txFnEndParam(txStylesheetCompilerState& 
 
     nsresult rv = aState.addVariable(var->mName);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(var.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    txCheckParam* checkParam = static_cast<txCheckParam*>(aState.popPtr());
+    txCheckParam* checkParam =
+        static_cast<txCheckParam*>(aState.popPtr(aState.eCheckParam));
     aState.addGotoTarget(&checkParam->mBailTarget);
 
     return NS_OK;
 }
 
 /*
   xsl:processing-instruction
 
@@ -2595,17 +2597,17 @@ txFnStartWhen(PRInt32 aNamespaceID,
     nsAutoPtr<Expr> test;
     rv = getExprAttr(aAttributes, aAttrCount, txXSLTAtoms::test, PR_TRUE,
                      aState, test);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txConditionalGoto> condGoto(new txConditionalGoto(test, nsnull));
     NS_ENSURE_TRUE(condGoto, NS_ERROR_OUT_OF_MEMORY);
 
-    rv = aState.pushPtr(condGoto);
+    rv = aState.pushPtr(condGoto, aState.eConditionalGoto);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(condGoto.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return aState.pushHandlerTable(gTxTemplateHandler);
 }
@@ -2620,17 +2622,17 @@ txFnEndWhen(txStylesheetCompilerState& a
     nsresult rv = aState.mChooseGotoList->add(gotoinstr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoPtr<txInstruction> instr(gotoinstr.forget());
     rv = aState.addInstruction(instr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     txConditionalGoto* condGoto =
-        static_cast<txConditionalGoto*>(aState.popPtr());
+        static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
     rv = aState.addGotoTarget(&condGoto->mTarget);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
 }
 
 /*
     xsl:with-param
--- a/content/xslt/src/xslt/txStylesheetCompiler.cpp
+++ b/content/xslt/src/xslt/txStylesheetCompiler.cpp
@@ -354,17 +354,17 @@ txStylesheetCompiler::startElementIntern
                  (aNamespaceID == kNameSpaceID_XSLT &&
                   attr.mNamespaceID == kNameSpaceID_None))) {
                 // XXX ErrorReport: unknown attribute
                 return NS_ERROR_XSLT_PARSE_FAILURE;
             }
         }
     }
 
-    rv = pushPtr(const_cast<txElementHandler*>(handler));
+    rv = pushPtr(const_cast<txElementHandler*>(handler), eElementHandler);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mElementContext->mDepth++;
 
     return NS_OK;
 }
 
 nsresult
@@ -391,17 +391,17 @@ txStylesheetCompiler::endElement()
             
             mInScopeVariables.RemoveElementAt(i);
             delete var;
         }
     }
 
     const txElementHandler* handler =
         const_cast<const txElementHandler*>
-                  (static_cast<txElementHandler*>(popPtr()));
+                  (static_cast<txElementHandler*>(popPtr(eElementHandler)));
     rv = (handler->mEndFunction)(*this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!--mElementContext->mDepth) {
         // this will delete the old object
         mElementContext = static_cast<txElementContext*>(popObject());
     }
 
@@ -648,45 +648,45 @@ txStylesheetCompilerState::~txStylesheet
     for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
         delete mInScopeVariables[i];
     }
 }
 
 nsresult
 txStylesheetCompilerState::pushHandlerTable(txHandlerTable* aTable)
 {
-    nsresult rv = pushPtr(mHandlerTable);
+    nsresult rv = pushPtr(mHandlerTable, eHandlerTable);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mHandlerTable = aTable;
 
     return NS_OK;
 }
 
 void
 txStylesheetCompilerState::popHandlerTable()
 {
-    mHandlerTable = static_cast<txHandlerTable*>(popPtr());
+    mHandlerTable = static_cast<txHandlerTable*>(popPtr(eHandlerTable));
 }
 
 nsresult
 txStylesheetCompilerState::pushSorter(txPushNewContext* aSorter)
 {
-    nsresult rv = pushPtr(mSorter);
+    nsresult rv = pushPtr(mSorter, ePushNewContext);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mSorter = aSorter;
 
     return NS_OK;
 }
 
 void
 txStylesheetCompilerState::popSorter()
 {
-    mSorter = static_cast<txPushNewContext*>(popPtr());
+    mSorter = static_cast<txPushNewContext*>(popPtr(ePushNewContext));
 }
 
 nsresult
 txStylesheetCompilerState::pushChooseGotoList()
 {
     nsresult rv = pushObject(mChooseGotoList);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -712,31 +712,41 @@ txStylesheetCompilerState::pushObject(Tx
 
 TxObject*
 txStylesheetCompilerState::popObject()
 {
     return static_cast<TxObject*>(mObjectStack.pop());
 }
 
 nsresult
-txStylesheetCompilerState::pushPtr(void* aPtr)
+txStylesheetCompilerState::pushPtr(void* aPtr, enumStackType aType)
 {
 #ifdef TX_DEBUG_STACK
-    PR_LOG(txLog::xslt, PR_LOG_DEBUG, ("pushPtr: %d\n", aPtr));
+    PR_LOG(txLog::xslt, PR_LOG_DEBUG, ("pushPtr: 0x%x type %u\n", aPtr, aType));
 #endif
+    mTypeStack.AppendElement(aType);
     return mOtherStack.push(aPtr);
 }
 
 void*
-txStylesheetCompilerState::popPtr()
+txStylesheetCompilerState::popPtr(enumStackType aType)
 {
+    PRUint32 stacklen = mTypeStack.Length();
+    NS_ABORT_IF_FALSE(stacklen > 0,
+                      "Attempt to pop when type stack is empty\n");
+    enumStackType type = mTypeStack.ElementAt(stacklen - 1);
+    mTypeStack.RemoveElementAt(stacklen - 1);
     void* value = mOtherStack.pop();
+    
 #ifdef TX_DEBUG_STACK
-    PR_LOG(txLog::xslt, PR_LOG_DEBUG, ("popPtr: %d\n", value));
+    PR_LOG(txLog::xslt, PR_LOG_DEBUG, ("popPtr: 0x%x type %u requested %u\n", value, type, aType));
 #endif
+    
+    NS_ABORT_IF_FALSE(type == aType,
+                      "Expected type does not match top element type on stack");
     return value;
 }
 
 nsresult
 txStylesheetCompilerState::addToplevelItem(txToplevelItem* aItem)
 {
     return mToplevelIterator.addBefore(aItem);
 }
--- a/content/xslt/src/xslt/txStylesheetCompiler.h
+++ b/content/xslt/src/xslt/txStylesheetCompiler.h
@@ -113,26 +113,38 @@ public:
         return mEmbedStatus == eInEmbed;
     }
     void doneEmbedding()
     {
         mEmbedStatus = eHasEmbed;
     }
 
     // Stack functions
+    enum enumStackType
+    {
+      eElementHandler,
+      eHandlerTable,
+      eVariableItem,
+      eCopy,
+      eInstruction,
+      ePushNewContext,
+      eConditionalGoto,
+      eCheckParam,
+      ePushNullTemplateRule
+    };
     nsresult pushHandlerTable(txHandlerTable* aTable);
     void popHandlerTable();
     nsresult pushSorter(txPushNewContext* aSorter);
     void popSorter();
     nsresult pushChooseGotoList();
     void popChooseGotoList();
     nsresult pushObject(TxObject* aObject);
     TxObject* popObject();
-    nsresult pushPtr(void* aPtr);
-    void* popPtr();
+    nsresult pushPtr(void* aPtr, enumStackType aType);
+    void* popPtr(enumStackType aType);
 
     // stylesheet functions
     nsresult addToplevelItem(txToplevelItem* aItem);
     nsresult openInstructionContainer(txInstructionContainer* aContainer);
     void closeInstructionContainer();
     nsresult addInstruction(nsAutoPtr<txInstruction> aInstruction);
     nsresult loadIncludedStylesheet(const nsAString& aURI);
     nsresult loadImportedStylesheet(const nsAString& aURI,
@@ -182,16 +194,17 @@ protected:
         eInEmbed,
         eHasEmbed
     } mEmbedStatus;
     nsString mStylesheetURI;
     PRPackedBool mIsTopCompiler;
     PRPackedBool mDoneWithThisStylesheet;
     txStack mObjectStack;
     txStack mOtherStack;
+    nsTArray<enumStackType> mTypeStack;
 
 private:
     txInstruction** mNextInstrPtr;
     txListIterator mToplevelIterator;
     nsTArray<txInstruction**> mGotoTargetPointers;
 };
 
 struct txStylesheetAttr