diff --git a/include/boost/regex/v5/basic_regex_creator.hpp b/include/boost/regex/v5/basic_regex_creator.hpp index 7e4ffcac..d9ae7807 100644 --- a/include/boost/regex/v5/basic_regex_creator.hpp +++ b/include/boost/regex/v5/basic_regex_creator.hpp @@ -974,7 +974,12 @@ template int basic_regex_creator::calculate_backstep(re_syntax_base* state) { typedef typename traits::char_class_type m_type; + int result = 0; + int last_alternative_result = -1; + + std::vector> stack; + while(state) { switch(state->type) @@ -993,9 +998,28 @@ int basic_regex_creator::calculate_backstep(re_syntax_base* state } break; case syntax_element_endmark: - if((static_cast(state)->index == -1) + if ((static_cast(state)->index == -1) || (static_cast(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; case syntax_element_literal: result += static_cast(state)->length; @@ -1051,11 +1075,13 @@ int basic_regex_creator::calculate_backstep(re_syntax_base* state continue; case syntax_element_alt: { - int r1 = calculate_backstep(state->next.p); - int r2 = calculate_backstep(static_cast(state)->alt.p); - if((r1 < 0) || (r1 != r2)) + // Push the alternative if we haven't pushed too many already: + if(stack.size() > BOOST_REGEX_MAX_BLOCKS) return -1; - return result + r1; + stack.push_back(std::make_tuple(result, static_cast(state)->alt.p)); + // and take the first one: + state = state->next.p; + continue; } default: break; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9140e2db..19f675fe 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -137,3 +137,5 @@ compile test_windows_defs_4.cpp ; run issue153.cpp : : : "msvc:-STACK:2097152" ; run issue227.cpp ; run issue232.cpp ; +run lookbehind_recursion_stress_test.cpp ; + diff --git a/test/lookbehind_recursion_stress_test.cpp b/test/lookbehind_recursion_stress_test.cpp new file mode 100644 index 00000000..feb5a449 --- /dev/null +++ b/test/lookbehind_recursion_stress_test.cpp @@ -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 + +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); +}