forked from boostorg/regex
Fix infinite recursion in bad recursive expressions.
Fix bug that allows invalid regex to go unnoticed and crash later. Fixes #5613. Fixes #5612. [SVN r72612]
This commit is contained in:
@ -241,6 +241,7 @@ protected:
|
||||
unsigned m_backrefs; // bitmask of permitted backrefs
|
||||
boost::uintmax_t m_bad_repeats; // bitmask of repeats we can't deduce a startmap for;
|
||||
bool m_has_recursions; // set when we have recursive expresisons to fixup
|
||||
std::vector<bool> m_recursion_checks; // notes which recursions we've followed while analysing this expression
|
||||
typename traits::char_class_type m_word_mask; // mask used to determine if a character is a word character
|
||||
typename traits::char_class_type m_mask_space; // mask used to determine if a character is a word character
|
||||
typename traits::char_class_type m_lower_mask; // mask used to determine if a character is a lowercase character
|
||||
@ -712,6 +713,8 @@ void basic_regex_creator<charT, traits>::finalize(const charT* p1, const charT*
|
||||
m_pdata->m_can_be_null = 0;
|
||||
|
||||
m_bad_repeats = 0;
|
||||
if(m_has_recursions)
|
||||
m_recursion_checks.assign(1 + m_pdata->m_mark_count, false);
|
||||
create_startmap(m_pdata->m_first_state, m_pdata->m_startmap, &(m_pdata->m_can_be_null), mask_all);
|
||||
// get the restart type:
|
||||
m_pdata->m_restart_type = get_restart_type(m_pdata->m_first_state);
|
||||
@ -948,9 +951,14 @@ void basic_regex_creator<charT, traits>::create_startmaps(re_syntax_base* state)
|
||||
state = state->next.p;
|
||||
}
|
||||
}
|
||||
|
||||
// now work through our list, building all the maps as we go:
|
||||
while(v.size())
|
||||
{
|
||||
// Initialize m_recursion_checks if we need it:
|
||||
if(m_has_recursions)
|
||||
m_recursion_checks.assign(1 + m_pdata->m_mark_count, false);
|
||||
|
||||
const std::pair<bool, re_syntax_base*>& p = v.back();
|
||||
m_icase = p.first;
|
||||
state = p.second;
|
||||
@ -960,6 +968,9 @@ void basic_regex_creator<charT, traits>::create_startmaps(re_syntax_base* state)
|
||||
m_bad_repeats = 0;
|
||||
create_startmap(state->next.p, static_cast<re_alt*>(state)->_map, &static_cast<re_alt*>(state)->can_be_null, mask_take);
|
||||
m_bad_repeats = 0;
|
||||
|
||||
if(m_has_recursions)
|
||||
m_recursion_checks.assign(1 + m_pdata->m_mark_count, false);
|
||||
create_startmap(static_cast<re_alt*>(state)->alt.p, static_cast<re_alt*>(state)->_map, &static_cast<re_alt*>(state)->can_be_null, mask_skip);
|
||||
// adjust the type of the state to allow for faster matching:
|
||||
state->type = this->get_repeat_type(state);
|
||||
@ -1114,7 +1125,11 @@ void basic_regex_creator<charT, traits>::create_startmap(re_syntax_base* state,
|
||||
}
|
||||
case syntax_element_recurse:
|
||||
{
|
||||
if(recursion_start == state)
|
||||
if(state->type == syntax_element_startmark)
|
||||
recursion_sub = static_cast<re_brace*>(state)->index;
|
||||
else
|
||||
recursion_sub = 0;
|
||||
if(m_recursion_checks[recursion_sub])
|
||||
{
|
||||
// Infinite recursion!!
|
||||
if(0 == this->m_pdata->m_status) // update the error code if not already set
|
||||
@ -1139,12 +1154,10 @@ void basic_regex_creator<charT, traits>::create_startmap(re_syntax_base* state,
|
||||
recursion_start = state;
|
||||
recursion_restart = state->next.p;
|
||||
state = static_cast<re_jump*>(state)->alt.p;
|
||||
if(state->type == syntax_element_startmark)
|
||||
recursion_sub = static_cast<re_brace*>(state)->index;
|
||||
else
|
||||
recursion_sub = 0;
|
||||
m_recursion_checks[recursion_sub] = true;
|
||||
break;
|
||||
}
|
||||
m_recursion_checks[recursion_sub] = true;
|
||||
// fall through, can't handle nested recursion here...
|
||||
}
|
||||
case syntax_element_backref:
|
||||
|
@ -1026,13 +1026,14 @@ bool basic_regex_parser<charT, traits>::parse_repeat(std::size_t low, std::size_
|
||||
{
|
||||
//
|
||||
// Check for illegal following quantifier, we have to do this here, because
|
||||
// the extra states we insert below circumvents are usual error checking :-(
|
||||
// the extra states we insert below circumvents our usual error checking :-(
|
||||
//
|
||||
switch(this->m_traits.syntax_type(*m_position))
|
||||
{
|
||||
case regex_constants::syntax_star:
|
||||
case regex_constants::syntax_plus:
|
||||
case regex_constants::syntax_question:
|
||||
case regex_constants::syntax_open_brace:
|
||||
fail(regex_constants::error_badrepeat, m_position - m_base);
|
||||
return false;
|
||||
}
|
||||
|
Reference in New Issue
Block a user