Skip to content

Commit 57ca082

Browse files
committed
Make backstep calculation non-recursive.
Refs #236.
1 parent 0cbaa4e commit 57ca082

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

include/boost/regex/v5/basic_regex_creator.hpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,12 @@ template <class charT, class traits>
974974
int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state)
975975
{
976976
typedef typename traits::char_class_type m_type;
977+
977978
int result = 0;
979+
int last_alternative_result = -1;
980+
981+
std::vector<std::tuple<int, re_syntax_base*>> stack;
982+
978983
while(state)
979984
{
980985
switch(state->type)
@@ -993,9 +998,28 @@ int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state
993998
}
994999
break;
9951000
case syntax_element_endmark:
996-
if((static_cast<re_brace*>(state)->index == -1)
1001+
if ((static_cast<re_brace*>(state)->index == -1)
9971002
|| (static_cast<re_brace*>(state)->index == -2))
998-
return result;
1003+
{
1004+
// We've finished the calculation, check against any previous alternatives:
1005+
if (last_alternative_result >= 0)
1006+
{
1007+
if (last_alternative_result != result)
1008+
return -1;
1009+
}
1010+
else
1011+
last_alternative_result = result;
1012+
1013+
if (stack.size())
1014+
{
1015+
// Skip to next alternative and calculate that as well:
1016+
std::tie(result, state) = stack.back();
1017+
stack.pop_back();
1018+
continue;
1019+
}
1020+
else
1021+
return result;
1022+
}
9991023
break;
10001024
case syntax_element_literal:
10011025
result += static_cast<re_literal*>(state)->length;
@@ -1051,11 +1075,13 @@ int basic_regex_creator<charT, traits>::calculate_backstep(re_syntax_base* state
10511075
continue;
10521076
case syntax_element_alt:
10531077
{
1054-
int r1 = calculate_backstep(state->next.p);
1055-
int r2 = calculate_backstep(static_cast<re_alt*>(state)->alt.p);
1056-
if((r1 < 0) || (r1 != r2))
1078+
// Push the alternative if we haven't pushed too many already:
1079+
if(stack.size() > BOOST_REGEX_MAX_BLOCKS)
10571080
return -1;
1058-
return result + r1;
1081+
stack.push_back(std::make_tuple(result, static_cast<re_alt*>(state)->alt.p));
1082+
// and take the first one:
1083+
state = state->next.p;
1084+
continue;
10591085
}
10601086
default:
10611087
break;

test/Jamfile.v2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,5 @@ compile test_windows_defs_4.cpp ;
137137
run issue153.cpp : : : "<toolset>msvc:<linkflags>-STACK:2097152" ;
138138
run issue227.cpp ;
139139
run issue232.cpp ;
140+
run lookbehind_recursion_stress_test.cpp ;
141+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
*
3+
* Copyright (c) 2024
4+
* John Maddock
5+
*
6+
* Use, modification and distribution are subject to the
7+
* Boost Software License, Version 1.0. (See accompanying file
8+
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9+
*
10+
*/
11+
12+
#include <boost/regex.hpp>
13+
14+
int main()
15+
{
16+
std::string s("(?<=(");
17+
s.append(1000, '|');
18+
s += "))";
19+
boost::regex rx(s);
20+
21+
s = "(?<=(a";
22+
for (unsigned i = 0; i < 1000; ++i)
23+
{
24+
s += "|a";
25+
}
26+
s += "))";
27+
boost::regex rx2(s);
28+
}

0 commit comments

Comments
 (0)