From 6246f5ec5183b5cf32fb488288ffc86c5b9ee36b Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Thu, 9 Nov 2017 11:23:54 +0000 Subject: [PATCH] Regex: Set a limit on how many recursions we allow. --- include/boost/regex/v4/perl_matcher.hpp | 4 +++- .../regex/v4/perl_matcher_non_recursive.hpp | 22 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/boost/regex/v4/perl_matcher.hpp b/include/boost/regex/v4/perl_matcher.hpp index 198acc27..1182b775 100644 --- a/include/boost/regex/v4/perl_matcher.hpp +++ b/include/boost/regex/v4/perl_matcher.hpp @@ -378,7 +378,7 @@ public: BidiIterator l_base) : m_result(what), base(first), last(end), position(first), backstop(l_base), re(e), traits_inst(e.get_traits()), - m_independent(false), next_count(&rep_obj), rep_obj(&next_count) + m_independent(false), next_count(&rep_obj), rep_obj(&next_count), m_recursions(0) { construct_init(e, f); } @@ -566,6 +566,8 @@ private: bool m_unwound_alt; // We are unwinding a commit - used by independent subs to determine whether to stop there or carry on unwinding: //bool m_unwind_commit; + // Recursion limit: + unsigned m_recursions; #endif // these operations aren't allowed, so are declared private, diff --git a/include/boost/regex/v4/perl_matcher_non_recursive.hpp b/include/boost/regex/v4/perl_matcher_non_recursive.hpp index 789226ba..3d89749d 100644 --- a/include/boost/regex/v4/perl_matcher_non_recursive.hpp +++ b/include/boost/regex/v4/perl_matcher_non_recursive.hpp @@ -143,6 +143,15 @@ struct saved_change_case : public saved_state saved_change_case(bool c) : saved_state(18), icase(c) {} }; +struct incrementer +{ + incrementer(unsigned* pu) : m_pu(pu) { ++*m_pu; } + ~incrementer() { --*m_pu; } + bool operator > (unsigned i) { return *m_pu > i; } +private: + unsigned* m_pu; +}; + template bool perl_matcher::match_all_states() { @@ -187,7 +196,9 @@ bool perl_matcher::match_all_states() &perl_matcher::match_commit, &perl_matcher::match_then, }; - + incrementer inc(&m_recursions); + if(inc > 80) + raise_error(traits_inst, regex_constants::error_complexity); push_recursion_stopper(); do{ while(pstate) @@ -1762,8 +1773,11 @@ bool perl_matcher::unwind_non_greedy_repeat(boo template bool perl_matcher::unwind_recursion(bool r) { + // We are backtracking back inside a recursion, need to push the info + // back onto the recursion stack, and do so unconditionally, otherwise + // we can get mismatched pushes and pops... saved_recursion* pmp = static_cast*>(m_backup_state); - if(!r) + if (!r) { recursion_stack.push_back(recursion_info()); recursion_stack.back().idx = pmp->recursion_id; @@ -1780,8 +1794,10 @@ bool perl_matcher::unwind_recursion(bool r) template bool perl_matcher::unwind_recursion_pop(bool r) { + // Backtracking out of a recursion, we must pop state off the recursion + // stack unconditionally to ensure matched pushes and pops: saved_state* pmp = static_cast(m_backup_state); - if(!r) + if (!r) { *m_presult = recursion_stack.back().results; position = recursion_stack.back().location_of_start;