From 1e19e25cd10c24f25beddff56b7c4b5fdc5adbcb Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Wed, 25 Oct 2017 14:32:14 -0400 Subject: Add in depth check for ToJavascript and related methods There exists a similar check for the parser, but it doesn't catch all cases of excessive memory usage, since a single parse step can generate multiple expressions that need to be converted or other cases where the parse depth doesn't match the emission depth later. Due to the expressions appearing in two different inheritence hierachies the depth information needs to be stored outside of the classes, thus the new depth class. Another way to handle this would be to change the method calls to take in a visitor object that tracks depth. This would require significant reworking of some of the code, so I am going to file a bug about doing that conversion as a cleanup. BUG=chromium:752495 Change-Id: Ica7c9b60ecf1e17530ea88b7bfb01582c63043be Reviewed-on: https://pdfium-review.googlesource.com/16752 Commit-Queue: Ryan Harrison Reviewed-by: Henrique Nakashima --- xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp | 2 + xfa/fxfa/fm2js/cxfa_fmexpression.cpp | 100 +++++++++++++++++++-- xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp | 5 ++ xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp | 95 +++++++++++++++++++- .../fm2js/cxfa_fmsimpleexpression_unittest.cpp | 7 ++ xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp | 21 +++++ xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h | 22 +++++ 7 files changed, 243 insertions(+), 9 deletions(-) create mode 100644 xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp create mode 100644 xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h (limited to 'xfa/fxfa/fm2js') diff --git a/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp b/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp index 00df0163f7..8c2aeefbbd 100644 --- a/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp +++ b/xfa/fxfa/fm2js/cxfa_fm2jscontext.cpp @@ -22,6 +22,7 @@ #include "third_party/base/stl_util.h" #include "xfa/fxfa/cxfa_ffnotify.h" #include "xfa/fxfa/fm2js/cxfa_fmparser.h" +#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" #include "xfa/fxfa/parser/cxfa_document.h" #include "xfa/fxfa/parser/cxfa_localevalue.h" #include "xfa/fxfa/parser/cxfa_node.h" @@ -6081,6 +6082,7 @@ bool CXFA_FM2JSContext::Translate(const WideStringView& wsFormcalc, if (!func || parser.HasError()) return false; + CXFA_FMToJavaScriptDepth::Reset(); if (!func->ToJavaScript(*wsJavascript)) return false; diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp index a1bbb50271..e8ab35ea67 100644 --- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp @@ -9,6 +9,7 @@ #include #include "core/fxcrt/cfx_widetextbuf.h" +#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" namespace { @@ -30,11 +31,13 @@ CXFA_FMExpression::CXFA_FMExpression(uint32_t line, XFA_FM_EXPTYPE type) : m_type(type), m_line(line) {} bool CXFA_FMExpression::ToJavaScript(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } bool CXFA_FMExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition( @@ -52,6 +55,10 @@ CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition( CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() {} bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + if (m_isGlobal && m_pExpressions.empty()) { javascript << L"// comments only"; return true; @@ -111,7 +118,8 @@ bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMFunctionDefinition::ToImpliedReturnJS(CFX_WideTextBuf&) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } CXFA_FMVarExpression::CXFA_FMVarExpression( @@ -125,6 +133,10 @@ CXFA_FMVarExpression::CXFA_FMVarExpression( CXFA_FMVarExpression::~CXFA_FMVarExpression() {} bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"var "; WideString tempName(m_wsName); if (m_wsName[0] == L'!') { @@ -149,6 +161,10 @@ bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMVarExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"var "; WideString tempName(m_wsName); if (m_wsName[0] == L'!') { @@ -185,6 +201,10 @@ CXFA_FMExpExpression::CXFA_FMExpExpression( CXFA_FMExpExpression::~CXFA_FMExpExpression() {} bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + bool ret = m_pExpression->ToJavaScript(javascript); if (m_pExpression->GetOperatorToken() != TOKassign) javascript << L";\n"; @@ -192,6 +212,10 @@ bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMExpExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + if (m_pExpression->GetOperatorToken() == TOKassign) return m_pExpression->ToImpliedReturnJS(javascript); @@ -227,6 +251,10 @@ CXFA_FMBlockExpression::CXFA_FMBlockExpression( CXFA_FMBlockExpression::~CXFA_FMBlockExpression() {} bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"{\n"; for (const auto& expr : m_ExpressionList) { if (!expr->ToJavaScript(javascript) || CFXA_IsTooBig(javascript)) @@ -237,6 +265,10 @@ bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMBlockExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"{\n"; for (const auto& expr : m_ExpressionList) { bool ret; @@ -259,10 +291,18 @@ CXFA_FMDoExpression::CXFA_FMDoExpression( CXFA_FMDoExpression::~CXFA_FMDoExpression() {} bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + return m_pList->ToJavaScript(javascript); } bool CXFA_FMDoExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + return m_pList->ToImpliedReturnJS(javascript); } @@ -279,6 +319,10 @@ CXFA_FMIfExpression::CXFA_FMIfExpression( CXFA_FMIfExpression::~CXFA_FMIfExpression() {} bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"if ("; if (m_pExpression) { javascript << XFA_FM_EXPTypeToString(GETFMVALUE); @@ -315,6 +359,10 @@ bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMIfExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"if ("; @@ -354,11 +402,13 @@ bool CXFA_FMIfExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { CXFA_FMLoopExpression::~CXFA_FMLoopExpression() {} bool CXFA_FMLoopExpression::ToJavaScript(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } bool CXFA_FMLoopExpression::ToImpliedReturnJS(CFX_WideTextBuf&) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } CXFA_FMWhileExpression::CXFA_FMWhileExpression( @@ -372,6 +422,10 @@ CXFA_FMWhileExpression::CXFA_FMWhileExpression( CXFA_FMWhileExpression::~CXFA_FMWhileExpression() {} bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"while ("; if (!m_pCondition->ToJavaScript(javascript)) return false; @@ -385,6 +439,10 @@ bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMWhileExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"while ("; @@ -405,6 +463,10 @@ CXFA_FMBreakExpression::CXFA_FMBreakExpression(uint32_t line) CXFA_FMBreakExpression::~CXFA_FMBreakExpression() {} bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"break;\n"; @@ -412,6 +474,10 @@ bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMBreakExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"break;\n"; @@ -424,6 +490,10 @@ CXFA_FMContinueExpression::CXFA_FMContinueExpression(uint32_t line) CXFA_FMContinueExpression::~CXFA_FMContinueExpression() {} bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"continue;\n"; @@ -431,6 +501,10 @@ bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMContinueExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"continue;\n"; @@ -456,6 +530,10 @@ CXFA_FMForExpression::CXFA_FMForExpression( CXFA_FMForExpression::~CXFA_FMForExpression() {} bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"{\nvar "; WideString tempVariant; if (m_wsVariant[0] == L'!') { @@ -509,6 +587,10 @@ bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMForExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"{\nvar "; @@ -577,6 +659,10 @@ CXFA_FMForeachExpression::CXFA_FMForeachExpression( CXFA_FMForeachExpression::~CXFA_FMForeachExpression() {} bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"{\n"; javascript << L"var "; if (m_wsIdentifier[0] == L'!') { @@ -632,6 +718,10 @@ bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMForeachExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << RUNTIMEFUNCTIONRETURNVALUE; javascript << L" = 0;\n"; javascript << L"{\n"; diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp index 192f935309..8582649fec 100644 --- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp @@ -10,6 +10,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" #include "third_party/base/ptr_util.h" +#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" TEST(CXFA_FMParserTest, Empty) { auto parser = pdfium::MakeUnique(L""); @@ -17,6 +18,7 @@ TEST(CXFA_FMParserTest, Empty) { ASSERT(ast != nullptr); EXPECT_FALSE(parser->HasError()); + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf buf; EXPECT_TRUE(ast->ToJavaScript(buf)); // TODO(dsinclair): This is a little weird ..... @@ -31,6 +33,7 @@ TEST(CXFA_FMParserTest, CommentOnlyIsError) { EXPECT_FALSE(parser->HasError()); // EXPECT_TRUE(parser->HasError()); + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf buf; EXPECT_TRUE(ast->ToJavaScript(buf)); EXPECT_EQ(L"// comments only", buf.AsStringView()); @@ -49,6 +52,7 @@ TEST(CXFA_FMParserTest, CommentThenValue) { ASSERT(ast != nullptr); EXPECT_FALSE(parser->HasError()); + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf buf; EXPECT_TRUE(ast->ToJavaScript(buf)); EXPECT_EQ(ret, buf.AsStringView()); @@ -104,6 +108,7 @@ TEST(CXFA_FMParserTest, Parse) { ASSERT(ast != nullptr); EXPECT_FALSE(parser->HasError()); + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf buf; EXPECT_TRUE(ast->ToJavaScript(buf)); EXPECT_EQ(ret, buf.AsStringView()); diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp index 3cfe0f52d5..86b7c91ec5 100644 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp @@ -7,11 +7,14 @@ #include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h" #include +#include #include +#include "core/fxcrt/autorestorer.h" #include "core/fxcrt/cfx_widetextbuf.h" #include "core/fxcrt/fx_extension.h" #include "third_party/base/logging.h" +#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" namespace { @@ -90,11 +93,13 @@ CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(uint32_t line, XFA_FM_TOKEN op) : m_line(line), m_op(op) {} bool CXFA_FMSimpleExpression::ToJavaScript(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } bool CXFA_FMSimpleExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } XFA_FM_TOKEN CXFA_FMSimpleExpression::GetOperatorToken() const { @@ -105,6 +110,10 @@ CXFA_FMNullExpression::CXFA_FMNullExpression(uint32_t line) : CXFA_FMSimpleExpression(line, TOKnull) {} bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"null"; return true; } @@ -116,6 +125,10 @@ CXFA_FMNumberExpression::CXFA_FMNumberExpression(uint32_t line, CXFA_FMNumberExpression::~CXFA_FMNumberExpression() {} bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << m_wsNumber; return true; } @@ -127,6 +140,10 @@ CXFA_FMStringExpression::CXFA_FMStringExpression(uint32_t line, CXFA_FMStringExpression::~CXFA_FMStringExpression() {} bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + WideString tempStr(m_wsString); if (tempStr.GetLength() <= 2) { javascript << tempStr; @@ -163,6 +180,10 @@ CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression( CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() {} bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + WideString tempStr(m_wsIdentifier); if (tempStr == L"$") { tempStr = L"this"; @@ -197,7 +218,8 @@ CXFA_FMUnaryExpression::CXFA_FMUnaryExpression( CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() {} bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } CXFA_FMBinExpression::CXFA_FMBinExpression( @@ -212,7 +234,8 @@ CXFA_FMBinExpression::CXFA_FMBinExpression( CXFA_FMBinExpression::~CXFA_FMBinExpression() {} bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf& javascript) { - return true; + CXFA_FMToJavaScriptDepth depthManager; + return depthManager.IsWithinMaxDepth(); } CXFA_FMAssignExpression::CXFA_FMAssignExpression( @@ -223,6 +246,10 @@ CXFA_FMAssignExpression::CXFA_FMAssignExpression( : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {} bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"if ("; javascript << gs_lpStrExpFuncName[ISFMOBJECT]; javascript << L"("; @@ -259,6 +286,10 @@ bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf& javascript) { } bool CXFA_FMAssignExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"if ("; javascript << gs_lpStrExpFuncName[ISFMOBJECT]; javascript << L"("; @@ -306,6 +337,10 @@ CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression( : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {} bool CXFA_FMLogicalOrExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[LOGICALOR]; javascript << L"("; if (!m_pExp1->ToJavaScript(javascript)) @@ -325,6 +360,10 @@ CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression( : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {} bool CXFA_FMLogicalAndExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[LOGICALAND]; javascript << L"("; if (!m_pExp1->ToJavaScript(javascript)) @@ -344,6 +383,10 @@ CXFA_FMEqualityExpression::CXFA_FMEqualityExpression( : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {} bool CXFA_FMEqualityExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + switch (m_op) { case TOKeq: case TOKkseq: @@ -375,6 +418,10 @@ CXFA_FMRelationalExpression::CXFA_FMRelationalExpression( : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {} bool CXFA_FMRelationalExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + switch (m_op) { case TOKlt: case TOKkslt: @@ -414,6 +461,10 @@ CXFA_FMAdditiveExpression::CXFA_FMAdditiveExpression( : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {} bool CXFA_FMAdditiveExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + switch (m_op) { case TOKplus: javascript << gs_lpStrExpFuncName[PLUS]; @@ -444,6 +495,10 @@ CXFA_FMMultiplicativeExpression::CXFA_FMMultiplicativeExpression( bool CXFA_FMMultiplicativeExpression::ToJavaScript( CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + switch (m_op) { case TOKmul: javascript << gs_lpStrExpFuncName[MULTIPLE]; @@ -471,6 +526,10 @@ CXFA_FMPosExpression::CXFA_FMPosExpression( : CXFA_FMUnaryExpression(line, TOKplus, std::move(pExp)) {} bool CXFA_FMPosExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[POSITIVE]; javascript << L"("; if (!m_pExp->ToJavaScript(javascript)) @@ -485,6 +544,10 @@ CXFA_FMNegExpression::CXFA_FMNegExpression( : CXFA_FMUnaryExpression(line, TOKminus, std::move(pExp)) {} bool CXFA_FMNegExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[NEGATIVE]; javascript << L"("; if (!m_pExp->ToJavaScript(javascript)) @@ -499,6 +562,10 @@ CXFA_FMNotExpression::CXFA_FMNotExpression( : CXFA_FMUnaryExpression(line, TOKksnot, std::move(pExp)) {} bool CXFA_FMNotExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[NOT]; javascript << L"("; if (!m_pExp->ToJavaScript(javascript)) @@ -553,6 +620,10 @@ uint32_t CXFA_FMCallExpression::IsMethodWithObjParam( } bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + CFX_WideTextBuf funcName; if (!m_pExp->ToJavaScript(funcName)) return false; @@ -666,6 +737,10 @@ CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression( CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() {} bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[DOT]; javascript << L"("; CFX_WideTextBuf tempExp1; @@ -713,6 +788,10 @@ CXFA_FMIndexExpression::CXFA_FMIndexExpression( m_bIsStarIndex(bIsStarIndex) {} bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + switch (m_accessorIndex) { case ACCESSOR_NO_INDEX: javascript << L"0"; @@ -757,6 +836,10 @@ CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() {} bool CXFA_FMDotDotAccessorExpression::ToJavaScript( CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << gs_lpStrExpFuncName[DOTDOT]; javascript << L"("; CFX_WideTextBuf tempExp1; @@ -790,6 +873,10 @@ CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression( std::move(pCallExp)) {} bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) { + CXFA_FMToJavaScriptDepth depthManager; + if (!depthManager.IsWithinMaxDepth()) + return false; + javascript << L"(\nfunction ()\n{\n"; javascript << L"var method_return_value = null;\n"; javascript << L"var accessor_object = "; diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp index 5f4d83c327..96ccb71ca9 100644 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp @@ -13,6 +13,7 @@ #include "testing/test_support.h" #include "third_party/base/ptr_util.h" #include "xfa/fxfa/fm2js/cxfa_fmlexer.h" +#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" TEST(FMCallExpressionTest, more_than_32_arguments) { // Use sign as it has 3 object parameters at positions 0, 5, and 6. @@ -22,6 +23,7 @@ TEST(FMCallExpressionTest, more_than_32_arguments) { for (size_t i = 0; i < 50; i++) args.push_back(pdfium::MakeUnique(0, TOKnan)); + CXFA_FMToJavaScriptDepth::Reset(); CXFA_FMCallExpression callExp(0, std::move(exp), std::move(args), true); CFX_WideTextBuf js; callExp.ToJavaScript(js); @@ -45,24 +47,28 @@ TEST(FMCallExpressionTest, more_than_32_arguments) { } TEST(FMStringExpressionTest, Empty) { + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf accumulator; CXFA_FMStringExpression(1, WideStringView()).ToJavaScript(accumulator); EXPECT_EQ(L"", accumulator.AsStringView()); } TEST(FMStringExpressionTest, Short) { + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf accumulator; CXFA_FMStringExpression(1, L"a").ToJavaScript(accumulator); EXPECT_EQ(L"a", accumulator.AsStringView()); } TEST(FMStringExpressionTest, Medium) { + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf accumulator; CXFA_FMStringExpression(1, L".abcd.").ToJavaScript(accumulator); EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView()); } TEST(FMStringExpressionTest, Long) { + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf accumulator; std::vector vec(140000, L'A'); CXFA_FMStringExpression(1, WideStringView(vec)).ToJavaScript(accumulator); @@ -70,6 +76,7 @@ TEST(FMStringExpressionTest, Long) { } TEST(FMStringExpressionTest, Quoted) { + CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf accumulator; CXFA_FMStringExpression(1, L".Simon says \"\"run\"\".") .ToJavaScript(accumulator); diff --git a/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp new file mode 100644 index 0000000000..6312ba6b3d --- /dev/null +++ b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp @@ -0,0 +1,21 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" + +namespace { + +// Arbitarily picked by looking at how deep a translation got before hitting +// the getting fuzzer memory limits. Should be larger then |kMaxParseDepth| in +// cxfa_fmparser.cpp. +const unsigned int kMaxDepth = 5000; + +} // namespace + +unsigned long CXFA_FMToJavaScriptDepth::depth_ = 0; +unsigned long CXFA_FMToJavaScriptDepth::max_depth_ = kMaxDepth; + +void CXFA_FMToJavaScriptDepth::Reset() { + depth_ = 0; +} diff --git a/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h new file mode 100644 index 0000000000..14f87a68f5 --- /dev/null +++ b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h @@ -0,0 +1,22 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef XFA_FXFA_FM2JS_CXFA_FMTOJAVASCRIPTDEPTH_H_ +#define XFA_FXFA_FM2JS_CXFA_FMTOJAVASCRIPTDEPTH_H_ + +class CXFA_FMToJavaScriptDepth { + public: + CXFA_FMToJavaScriptDepth() { depth_++; } + ~CXFA_FMToJavaScriptDepth() { depth_--; } + + bool IsWithinMaxDepth() const { return depth_ <= max_depth_; } + + static void Reset(); + + private: + static unsigned long depth_; + static unsigned long max_depth_; +}; + +#endif // XFA_FXFA_FM2JS_CXFA_FMTOJAVASCRIPTDEPTH_H_ -- cgit v1.2.3