Skip to content

Commit 0cbaa4e

Browse files
authored
fix #232 (#234)
* add failing test case * fix issue #232 Credit to OSS-Fuzz for finding the problematic test regexes and configurations.
1 parent f0afa5d commit 0cbaa4e

File tree

4 files changed

+94
-14
lines changed

4 files changed

+94
-14
lines changed

include/boost/regex/v5/perl_matcher.hpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,34 @@
3939
#endif
4040
#endif
4141

42+
#ifndef BOOST_REGEX_STANDALONE
43+
# define BOOST_REGEX_DETAIL_THROW(ex) boost::throw_exception(ex)
44+
#else
45+
# define BOOST_REGEX_DETAIL_THROW(ex) throw ex
46+
#endif
47+
4248
namespace boost{
4349
namespace BOOST_REGEX_DETAIL_NS{
4450

4551
//
4652
// error checking API:
4753
//
48-
inline void verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf)
54+
inline void verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf)
4955
{
56+
auto is_perl = (mf & match_perl);
57+
auto is_posix = (mf & match_posix);
58+
59+
if (is_perl && is_posix)
60+
{
61+
BOOST_REGEX_DETAIL_THROW(std::logic_error("Usage Error: Can't mix Perl and POSIX matching rules"));
62+
}
63+
5064
//
5165
// can't mix match_extra with POSIX matching rules:
5266
//
53-
if ((mf & match_extra) && (mf & match_posix))
67+
if ((mf & match_extra) && is_posix)
5468
{
55-
std::logic_error msg("Usage Error: Can't mix regular expression captures with POSIX matching rules");
56-
#ifndef BOOST_REGEX_STANDALONE
57-
throw_exception(msg);
58-
#else
59-
throw msg;
60-
#endif
69+
BOOST_REGEX_DETAIL_THROW(std::logic_error("Usage Error: Can't mix regular expression captures with POSIX matching rules"));
6170
}
6271
}
6372
//

include/boost/regex/v5/perl_matcher_common.hpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,7 @@ void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_r
6060
if(e.empty())
6161
{
6262
// precondition failure: e is not a valid regex.
63-
std::invalid_argument ex("Invalid regular expression object");
64-
#ifndef BOOST_REGEX_STANDALONE
65-
boost::throw_exception(ex);
66-
#else
67-
throw e;
68-
#endif
63+
BOOST_REGEX_DETAIL_THROW(std::invalid_argument("Invalid regular expression object"));
6964
}
7065
pstate = 0;
7166
m_match_flags = f;
@@ -98,7 +93,11 @@ void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_r
9893
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);
9994
// Disable match_any if requested in the state machine:
10095
if(e.get_data().m_disable_match_any)
96+
{
97+
if (m_match_flags & match_posix)
98+
BOOST_REGEX_DETAIL_THROW(std::logic_error("Invalid regex for POSIX-style matching"));
10199
m_match_flags &= regex_constants::match_not_any;
100+
}
102101
}
103102
#ifdef BOOST_REGEX_MSVC
104103
# pragma warning(pop)

test/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,4 @@ compile test_windows_defs_4.cpp ;
136136

137137
run issue153.cpp : : : "<toolset>msvc:<linkflags>-STACK:2097152" ;
138138
run issue227.cpp ;
139+
run issue232.cpp ;

test/issue232.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <boost/core/lightweight_test.hpp>
2+
3+
#include <boost/regex.hpp>
4+
#include <cstddef>
5+
#include <vector>
6+
7+
template<std::size_t N0, std::size_t N = N0 - 1>
8+
void tester( char const (&str)[ N0 ] )
9+
{
10+
std::vector<char> s(N, '\0');
11+
std::memcpy(s.data(), str, N);
12+
boost::regex rx(s.begin(), s.end());
13+
14+
std::vector<std::string> wheres;
15+
wheres.push_back(std::string(15, 'H'));
16+
wheres.push_back("");
17+
wheres.push_back(" ");
18+
19+
// Perl-style matching
20+
for (auto const& where : wheres) {
21+
boost::match_results<std::string::const_iterator> what;
22+
bool match = boost::regex_match(where, what, rx, boost::match_default | boost::match_partial | boost::match_any | boost::match_perl);
23+
(void) match;
24+
}
25+
26+
// POSIX-style matching
27+
for (auto const& where : wheres) {
28+
try {
29+
boost::match_results<std::string::const_iterator> what;
30+
bool match = boost::regex_match(where, what, rx, boost::match_default | boost::match_partial | boost::match_any | boost::match_posix);
31+
(void) match;
32+
} catch(...) {}
33+
}
34+
35+
}
36+
37+
int main()
38+
{
39+
// test strings derived from fuzzing
40+
// we keep a simple human-readable version
41+
char const str1[] = "(Y(*COMMIT)|\\K\\D|.)+";
42+
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]*+";
43+
char const str3[] = "(Y(*COMMIT)\xFF\x80|\\L\\K||||||||||.|||||\x84|||||\x00\x00\x10||||||.* .'?-i)[L??...-i)[L??...[\x00\x14R]*+";
44+
char const str4[] = "(Y(*COMMIT)\x96||.* .* .\\K|||\x9F||||\x9C|.|||||\x84\x99|||\x01\x00\x00\x00|||'?-i#PL\x00\x01.\x86??OMMIT)?...[\x00\x14R]*+";
45+
46+
tester(str1);
47+
tester(str2);
48+
tester(str3);
49+
tester(str4);
50+
51+
// prove that we catch certain impossible scenarios
52+
53+
{
54+
char const* str = "abcd";
55+
boost::regex rx(str);
56+
boost::match_results<std::string::const_iterator> what;
57+
std::string where(15, 'H');
58+
BOOST_TEST_THROWS(boost::regex_match(where, rx, boost::match_posix | boost::match_perl), std::logic_error);
59+
}
60+
61+
{
62+
char const* str = "ab(*COMMIT)cd";
63+
boost::regex rx(str);
64+
boost::match_results<std::string::const_iterator> what;
65+
std::string where(15, 'H');
66+
BOOST_TEST_THROWS(boost::regex_match(where, rx, boost::match_posix), std::logic_error);
67+
}
68+
69+
return boost::report_errors();
70+
}
71+

0 commit comments

Comments
 (0)