Make backstep calculation non-recursive.

Refs https://github.com/boostorg/regex/pull/236.
This commit is contained in:
jzmaddock
2024-12-16 16:58:25 +00:00
parent 0cbaa4ef17
commit 57ca08240e
3 changed files with 62 additions and 6 deletions

View File

@ -974,7 +974,12 @@ template <class charT, class traits>
int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state) int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state)
{ {
typedef typename traits::char_class_type m_type; typedef typename traits::char_class_type m_type;
int result = 0; int result = 0;
int last_alternative_result = -1;
std::vector<std::tuple<int, re_syntax_base*>> stack;
while(state) while(state)
{ {
switch(state->type) switch(state->type)
@ -993,9 +998,28 @@ int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state
} }
break; break;
case syntax_element_endmark: case syntax_element_endmark:
if((static_cast<re_brace*>(state)->index == -1) if ((static_cast<re_brace*>(state)->index == -1)
|| (static_cast<re_brace*>(state)->index == -2)) || (static_cast<re_brace*>(state)->index == -2))
return result; {
// We've finished the calculation, check against any previous alternatives:
if (last_alternative_result >= 0)
{
if (last_alternative_result != result)
return -1;
}
else
last_alternative_result = result;
if (stack.size())
{
// Skip to next alternative and calculate that as well:
std::tie(result, state) = stack.back();
stack.pop_back();
continue;
}
else
return result;
}
break; break;
case syntax_element_literal: case syntax_element_literal:
result += static_cast<re_literal*>(state)->length; result += static_cast<re_literal*>(state)->length;
@ -1051,11 +1075,13 @@ int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state
continue; continue;
case syntax_element_alt: case syntax_element_alt:
{ {
int r1 = calculate_backstep(state->next.p); // Push the alternative if we haven't pushed too many already:
int r2 = calculate_backstep(static_cast<re_alt*>(state)->alt.p); if(stack.size() > BOOST_REGEX_MAX_BLOCKS)
if((r1 < 0) || (r1 != r2))
return -1; return -1;
return result + r1; stack.push_back(std::make_tuple(result, static_cast<re_alt*>(state)->alt.p));
// and take the first one:
state = state->next.p;
continue;
} }
default: default:
break; break;

View File

@ -137,3 +137,5 @@ compile test_windows_defs_4.cpp ;
run issue153.cpp : : : "<toolset>msvc:<linkflags>-STACK:2097152" ; run issue153.cpp : : : "<toolset>msvc:<linkflags>-STACK:2097152" ;
run issue227.cpp ; run issue227.cpp ;
run issue232.cpp ; run issue232.cpp ;
run lookbehind_recursion_stress_test.cpp ;

View File

@ -0,0 +1,28 @@
/*
*
* Copyright (c) 2024
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#include <boost/regex.hpp>
int main()
{
std::string s("(?<=(");
s.append(1000, '|');
s += "))";
boost::regex rx(s);
s = "(?<=(a";
for (unsigned i = 0; i < 1000; ++i)
{
s += "|a";
}
s += "))";
boost::regex rx2(s);
}