Implement recursion limit for AST expressions which don't use a separate stack frame

fixes #11106
This commit is contained in:
Gunnar Beutner 2016-03-23 08:40:32 +01:00
parent 71060be89a
commit 6ba0c5fe01
3 changed files with 33 additions and 5 deletions

View File

@ -26,13 +26,13 @@ using namespace icinga;
boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames; boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames;
ScriptFrame::ScriptFrame(void) ScriptFrame::ScriptFrame(void)
: Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false) : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0)
{ {
PushFrame(this); PushFrame(this);
} }
ScriptFrame::ScriptFrame(const Value& self) ScriptFrame::ScriptFrame(const Value& self)
: Locals(new Dictionary()), Self(self), Sandboxed(false) : Locals(new Dictionary()), Self(self), Sandboxed(false), Depth(0)
{ {
PushFrame(this); PushFrame(this);
} }
@ -43,6 +43,19 @@ ScriptFrame::~ScriptFrame(void)
ASSERT(frame == this); 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) ScriptFrame *ScriptFrame::GetCurrentFrame(void)
{ {
std::stack<ScriptFrame *> *frames = m_ScriptFrames.get(); std::stack<ScriptFrame *> *frames = m_ScriptFrames.get();
@ -72,8 +85,10 @@ void ScriptFrame::PushFrame(ScriptFrame *frame)
m_ScriptFrames.reset(frames); m_ScriptFrames.reset(frames);
} }
if (frames->size() > 500) if (!frames->empty()) {
BOOST_THROW_EXCEPTION(ScriptError("Recursion level too deep.")); ScriptFrame *parent = frames->top();
frame->Depth += parent->Depth;
}
frames->push(frame); frames->push(frame);
} }

View File

@ -33,11 +33,15 @@ struct I2_BASE_API ScriptFrame
Dictionary::Ptr Locals; Dictionary::Ptr Locals;
Value Self; Value Self;
bool Sandboxed; bool Sandboxed;
int Depth;
ScriptFrame(void); ScriptFrame(void);
ScriptFrame(const Value& self); ScriptFrame(const Value& self);
~ScriptFrame(void); ~ScriptFrame(void);
void IncreaseStackDepth(void);
void DecreaseStackDepth(void);
static ScriptFrame *GetCurrentFrame(void); static ScriptFrame *GetCurrentFrame(void);
private: private:

View File

@ -61,14 +61,23 @@ ExpressionResult Expression::Evaluate(ScriptFrame& frame, DebugHint *dhint) cons
<< "Executing:\n" << msgbuf.str();*/ << "Executing:\n" << msgbuf.str();*/
#endif /* I2_DEBUG */ #endif /* I2_DEBUG */
return DoEvaluate(frame, dhint); frame.IncreaseStackDepth();
ExpressionResult result = DoEvaluate(frame, dhint);
frame.DecreaseStackDepth();
return result;
} catch (ScriptError& ex) { } catch (ScriptError& ex) {
frame.DecreaseStackDepth();
ScriptBreakpoint(frame, &ex, GetDebugInfo()); ScriptBreakpoint(frame, &ex, GetDebugInfo());
throw; throw;
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
frame.DecreaseStackDepth();
BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo()) BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo())
<< boost::errinfo_nested_exception(boost::current_exception())); << boost::errinfo_nested_exception(boost::current_exception()));
} }
frame.DecreaseStackDepth();
} }
bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const bool Expression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const