Skip to content

Commit

Permalink
fix #232 (#234)
Browse files Browse the repository at this point in the history
* add failing test case
* fix issue #232
Credit to OSS-Fuzz for finding the problematic test regexes and configurations.
  • Loading branch information
cmazakas authored Dec 5, 2024
1 parent f0afa5d commit 0cbaa4e
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 14 deletions.
25 changes: 17 additions & 8 deletions include/boost/regex/v5/perl_matcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
}
//
Expand Down
11 changes: 5 additions & 6 deletions include/boost/regex/v5/perl_matcher_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,7 @@ void perl_matcher<BidiIterator, Allocator, traits>::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;
Expand Down Expand Up @@ -98,7 +93,11 @@ void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_r
match_any_mask = static_cast<unsigned char>((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)
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,4 @@ compile test_windows_defs_4.cpp ;

run issue153.cpp : : : "<toolset>msvc:<linkflags>-STACK:2097152" ;
run issue227.cpp ;
run issue232.cpp ;
71 changes: 71 additions & 0 deletions test/issue232.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <boost/core/lightweight_test.hpp>

#include <boost/regex.hpp>
#include <cstddef>
#include <vector>

template<std::size_t N0, std::size_t N = N0 - 1>
void tester( char const (&str)[ N0 ] )
{
std::vector<char> s(N, '\0');
std::memcpy(s.data(), str, N);
boost::regex rx(s.begin(), s.end());

std::vector<std::string> 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<std::string::const_iterator> 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<std::string::const_iterator> 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<std::string::const_iterator> 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<std::string::const_iterator> what;
std::string where(15, 'H');
BOOST_TEST_THROWS(boost::regex_match(where, rx, boost::match_posix), std::logic_error);
}

return boost::report_errors();
}

0 comments on commit 0cbaa4e

Please sign in to comment.