Skip to content

Commit

Permalink
Implement recursion limit for AST expressions which don't use a separ…
Browse files Browse the repository at this point in the history
…ate stack frame

fixes #11106
  • Loading branch information
gunnarbeutner committed Apr 20, 2016
1 parent 97f324a commit ba3eeaf
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 5 deletions.
23 changes: 19 additions & 4 deletions lib/base/scriptframe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ using namespace icinga;
boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames;

ScriptFrame::ScriptFrame(void)
: Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false)
: Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0)
{
PushFrame(this);
}

ScriptFrame::ScriptFrame(const Value& self)
: Locals(new Dictionary()), Self(self), Sandboxed(false)
: Locals(new Dictionary()), Self(self), Sandboxed(false), Depth(0)
{
PushFrame(this);
}
Expand All @@ -43,6 +43,19 @@ ScriptFrame::~ScriptFrame(void)
ASSERT(frame == this);
}

void ScriptFrame::IncreaseStackDepth(void)
{
if (Depth + 1 > 300)
BOOST_THROW_EXCEPTION(ScriptError("Stack overflow while evaluating expression: Recursion level too deep."));

Depth++;
}

void ScriptFrame::DecreaseStackDepth(void)
{
Depth--;
}

ScriptFrame *ScriptFrame::GetCurrentFrame(void)
{
std::stack<ScriptFrame *> *frames = m_ScriptFrames.get();
Expand Down Expand Up @@ -72,8 +85,10 @@ void ScriptFrame::PushFrame(ScriptFrame *frame)
m_ScriptFrames.reset(frames);
}

if (frames->size() > 500)
BOOST_THROW_EXCEPTION(ScriptError("Recursion level too deep."));
if (!frames->empty()) {
ScriptFrame *parent = frames->top();
frame->Depth += parent->Depth;
}

frames->push(frame);
}
4 changes: 4 additions & 0 deletions lib/base/scriptframe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ struct I2_BASE_API ScriptFrame
Dictionary::Ptr Locals;
Value Self;
bool Sandboxed;
int Depth;

ScriptFrame(void);
ScriptFrame(const Value& self);
~ScriptFrame(void);

void IncreaseStackDepth(void);
void DecreaseStackDepth(void);

static ScriptFrame *GetCurrentFrame(void);

private:
Expand Down
11 changes: 10 additions & 1 deletion lib/config/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,23 @@ ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) cons
<< "Executing:\n" << msgbuf.str();*/
#endif /* I2_DEBUG */

return DoEvaluate(frame, dhint);
frame.IncreaseStackDepth();
ExpressionResult result = DoEvaluate(frame, dhint);
frame.DecreaseStackDepth();
return result;
} catch (ScriptError& ex) {
frame.DecreaseStackDepth();

ScriptBreakpoint(frame, &ex, GetDebugInfo());
throw;
} catch (const std::exception& ex) {
frame.DecreaseStackDepth();

BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo())
<< boost::errinfo_nested_exception(boost::current_exception()));
}

frame.DecreaseStackDepth();
}

bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
Expand Down

0 comments on commit ba3eeaf

Please sign in to comment.