diff --git a/include/boost/regex/v5/perl_matcher.hpp b/include/boost/regex/v5/perl_matcher.hpp index e48171085..207daedd8 100644 --- a/include/boost/regex/v5/perl_matcher.hpp +++ b/include/boost/regex/v5/perl_matcher.hpp @@ -39,25 +39,34 @@ #endif #endif +#ifndef BOOST_REGEX_STANDALONE +# define BOOST_REGEX_DETAIL_THROW(ex) boost::throw_exception(ex) +#else +# define BOOST_REGEX_DETAIL_THROW(ex) throw ex +#endif + namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ // // error checking API: // -inline void verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf) +inline void verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf) { + auto is_perl = (mf & match_perl); + auto is_posix = (mf & match_posix); + + if (is_perl && is_posix) + { + BOOST_REGEX_DETAIL_THROW(std::logic_error("Usage Error: Can't mix Perl and POSIX matching rules")); + } + // // can't mix match_extra with POSIX matching rules: // - if ((mf & match_extra) && (mf & match_posix)) + if ((mf & match_extra) && is_posix) { - std::logic_error msg("Usage Error: Can't mix regular expression captures with POSIX matching rules"); -#ifndef BOOST_REGEX_STANDALONE - throw_exception(msg); -#else - throw msg; -#endif + BOOST_REGEX_DETAIL_THROW(std::logic_error("Usage Error: Can't mix regular expression captures with POSIX matching rules")); } } // diff --git a/include/boost/regex/v5/perl_matcher_common.hpp b/include/boost/regex/v5/perl_matcher_common.hpp index 4e9119e3e..ff3a69e88 100644 --- a/include/boost/regex/v5/perl_matcher_common.hpp +++ b/include/boost/regex/v5/perl_matcher_common.hpp @@ -60,12 +60,7 @@ void perl_matcher::construct_init(const basic_r if(e.empty()) { // precondition failure: e is not a valid regex. - std::invalid_argument ex("Invalid regular expression object"); -#ifndef BOOST_REGEX_STANDALONE - boost::throw_exception(ex); -#else - throw e; -#endif + BOOST_REGEX_DETAIL_THROW(std::invalid_argument("Invalid regular expression object")); } pstate = 0; m_match_flags = f; @@ -98,7 +93,11 @@ void perl_matcher::construct_init(const basic_r match_any_mask = static_cast((f & match_not_dot_newline) ? BOOST_REGEX_DETAIL_NS::test_not_newline : BOOST_REGEX_DETAIL_NS::test_newline); // Disable match_any if requested in the state machine: if(e.get_data().m_disable_match_any) + { + if (m_match_flags & match_posix) + BOOST_REGEX_DETAIL_THROW(std::logic_error("Invalid regex for POSIX-style matching")); m_match_flags &= regex_constants::match_not_any; + } } #ifdef BOOST_REGEX_MSVC # pragma warning(pop) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1fd6cc3d0..9140e2db3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -136,3 +136,4 @@ compile test_windows_defs_4.cpp ; run issue153.cpp : : : "msvc:-STACK:2097152" ; run issue227.cpp ; +run issue232.cpp ; diff --git a/test/issue232.cpp b/test/issue232.cpp new file mode 100644 index 000000000..a8c2b2ccd --- /dev/null +++ b/test/issue232.cpp @@ -0,0 +1,71 @@ +#include + +#include +#include +#include + +template +void tester( char const (&str)[ N0 ] ) +{ + std::vector s(N, '\0'); + std::memcpy(s.data(), str, N); + boost::regex rx(s.begin(), s.end()); + + std::vector wheres; + wheres.push_back(std::string(15, 'H')); + wheres.push_back(""); + wheres.push_back(" "); + + // Perl-style matching + for (auto const& where : wheres) { + boost::match_results what; + bool match = boost::regex_match(where, what, rx, boost::match_default | boost::match_partial | boost::match_any | boost::match_perl); + (void) match; + } + + // POSIX-style matching + for (auto const& where : wheres) { + try { + boost::match_results what; + bool match = boost::regex_match(where, what, rx, boost::match_default | boost::match_partial | boost::match_any | boost::match_posix); + (void) match; + } catch(...) {} + } + +} + +int main() +{ + // test strings derived from fuzzing + // we keep a simple human-readable version + char const str1[] = "(Y(*COMMIT)|\\K\\D|.)+"; + char const str2[] = "(Y(*COMMIT){||\\K\\D|||||||||\\K|||ss|||||.|\232*(?(50)\027\0204657|H)\020}\031\000.* 6.'?-i)+[L??.\000\000\000\004\000\000\000\000?..<[\000\024R]*+"; + char const str3[] = "(Y(*COMMIT)\xFF\x80|\\L\\K||||||||||.|||||\x84|||||\x00\x00\x10||||||.* .'?-i)[L??...-i)[L??...[\x00\x14R]*+"; + char const str4[] = "(Y(*COMMIT)\x96||.* .* .\\K|||\x9F||||\x9C|.|||||\x84\x99|||\x01\x00\x00\x00|||'?-i#PL\x00\x01.\x86??OMMIT)?...[\x00\x14R]*+"; + + tester(str1); + tester(str2); + tester(str3); + tester(str4); + + // prove that we catch certain impossible scenarios + + { + char const* str = "abcd"; + boost::regex rx(str); + boost::match_results what; + std::string where(15, 'H'); + BOOST_TEST_THROWS(boost::regex_match(where, rx, boost::match_posix | boost::match_perl), std::logic_error); + } + + { + char const* str = "ab(*COMMIT)cd"; + boost::regex rx(str); + boost::match_results what; + std::string where(15, 'H'); + BOOST_TEST_THROWS(boost::regex_match(where, rx, boost::match_posix), std::logic_error); + } + + return boost::report_errors(); +} +