From afc4229234db812700537c67190e480bc73d3651 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Thu, 23 Jan 2020 19:24:33 +0000 Subject: [PATCH] Fix recursive expressions where the recursion appears more than once. Fixes https://github.com/boostorg/regex/issues/87. Also fix some more msvc warnings. --- include/boost/regex/v4/basic_regex_creator.hpp | 14 +++++++++++++- include/boost/regex/v4/basic_regex_parser.hpp | 4 ++-- include/boost/regex/v4/w32_regex_traits.hpp | 2 +- src/c_regex_traits.cpp | 2 +- test/regress/test_perl_ex.cpp | 1 + 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/boost/regex/v4/basic_regex_creator.hpp b/include/boost/regex/v4/basic_regex_creator.hpp index 611d34b4..f4b1660a 100644 --- a/include/boost/regex/v4/basic_regex_creator.hpp +++ b/include/boost/regex/v4/basic_regex_creator.hpp @@ -594,7 +594,7 @@ re_syntax_base* basic_regex_creator::append_set( return 0; } // everything in range matches: - std::memset(result->_map + static_cast(c1), true, 1 + static_cast(c2) - static_cast(c1)); + std::memset(result->_map + static_cast(c1), true, static_cast(1u) + static_cast(static_cast(c2) - static_cast(c1))); } } // @@ -1070,9 +1070,21 @@ int basic_regex_creator::calculate_backstep(re_syntax_base* state return -1; } +struct recursion_saver +{ + std::vector saved_state; + std::vector* state; + recursion_saver(std::vector* p) : saved_state(*p), state(p) {} + ~recursion_saver() + { + state->swap(saved_state); + } +}; + template void basic_regex_creator::create_startmap(re_syntax_base* state, unsigned char* l_map, unsigned int* pnull, unsigned char mask) { + recursion_saver saved_recursions(&m_recursion_checks); int not_last_jump = 1; re_syntax_base* recursion_start = 0; int recursion_sub = 0; diff --git a/include/boost/regex/v4/basic_regex_parser.hpp b/include/boost/regex/v4/basic_regex_parser.hpp index ff52f329..8bdb079f 100644 --- a/include/boost/regex/v4/basic_regex_parser.hpp +++ b/include/boost/regex/v4/basic_regex_parser.hpp @@ -197,7 +197,7 @@ void basic_regex_parser::parse(const charT* p1, const charT* p2, if(this->m_pdata->m_status) return; // fill in our sub-expression count: - this->m_pdata->m_mark_count = 1 + m_mark_count; + this->m_pdata->m_mark_count = 1u + (std::size_t)m_mark_count; this->finalize(p1, p2); } @@ -2723,7 +2723,7 @@ option_group_jump: { #ifndef BOOST_NO_STD_DISTANCE if(this->flags() & regbase::save_subexpression_location) - this->m_pdata->m_subs.at(markid - 1).second = std::distance(m_base, m_position) - 1; + this->m_pdata->m_subs.at((std::size_t)markid - 1).second = std::distance(m_base, m_position) - 1; #else if(this->flags() & regbase::save_subexpression_location) this->m_pdata->m_subs.at(markid - 1).second = (m_position - m_base) - 1; diff --git a/include/boost/regex/v4/w32_regex_traits.hpp b/include/boost/regex/v4/w32_regex_traits.hpp index 378ee856..f869e58a 100644 --- a/include/boost/regex/v4/w32_regex_traits.hpp +++ b/include/boost/regex/v4/w32_regex_traits.hpp @@ -546,7 +546,7 @@ typename w32_regex_traits_implementation::char_class_type if(pos != m_custom_class_names.end()) return pos->second; } - std::size_t state_id = 1 + BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + std::size_t state_id = 1u + (std::size_t)BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); if(state_id < sizeof(masks) / sizeof(masks[0])) return masks[state_id]; return masks[0]; diff --git a/src/c_regex_traits.cpp b/src/c_regex_traits.cpp index a0b52ee4..09300666 100644 --- a/src/c_regex_traits.cpp +++ b/src/c_regex_traits.cpp @@ -157,7 +157,7 @@ c_regex_traits::char_class_type BOOST_REGEX_CALL c_regex_traits::loo s[i] = static_cast((std::tolower)(static_cast(s[i]))); idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); } - BOOST_ASSERT(std::size_t(idx+1) < sizeof(masks) / sizeof(masks[0])); + BOOST_ASSERT(std::size_t(idx) + 1u < sizeof(masks) / sizeof(masks[0])); return masks[idx+1]; } diff --git a/test/regress/test_perl_ex.cpp b/test/regress/test_perl_ex.cpp index 6a53256d..2a7310cd 100644 --- a/test/regress/test_perl_ex.cpp +++ b/test/regress/test_perl_ex.cpp @@ -935,6 +935,7 @@ void test_recursion() TEST_REGEX_SEARCH("namespace\\s+(\\w+)\\s+(\\{(?:[^{}]*(?:(?2)[^{}]*)*)?\\})", perl, "namespace one { namespace two { int foo(){} } { {{{ } } } } {}}", match_default, make_array(0, 64, 10, 13, 14, 64, -2, -2)); TEST_INVALID_REGEX("((?1)|a)", perl); TEST_REGEX_SEARCH("a(?0)?", perl, "aaaaa", match_default, make_array(0, 5, -2, -2)); + TEST_REGEX_SEARCH("((?(DEFINE)(?'a'A)(?'b'(?&a)?(?&a)))(?&b)?)", perl, "AA", match_default, make_array(0, 2, 0, 2, -1, -1, -2, 2, 2, 2, 2, -1, -1, -2, -2)); // Recursion to a named sub with a name that is used multiple times: TEST_REGEX_SEARCH("(?:(?a+)|(?b+))\\.(?&A)", perl, "aaaa.aa", match_default, make_array(0, 7, 0, 4, -1, -1, -2, -2));