mirror of
https://github.com/boostorg/regex.git
synced 2025-07-14 12:56:36 +02:00
Added throw if the number of searched states grows too large.
[SVN r15372]
This commit is contained in:
@ -26,6 +26,12 @@
|
|||||||
#ifndef BOOST_REGEX_MATCH_HPP
|
#ifndef BOOST_REGEX_MATCH_HPP
|
||||||
#define BOOST_REGEX_MATCH_HPP
|
#define BOOST_REGEX_MATCH_HPP
|
||||||
|
|
||||||
|
#ifndef BOOST_REGEX_MAX_STATE_COUNT
|
||||||
|
# define BOOST_REGEX_MAX_STATE_COUNT 100000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
namespace re_detail{
|
namespace re_detail{
|
||||||
@ -175,6 +181,7 @@ class _priv_match_data
|
|||||||
public:
|
public:
|
||||||
typedef typename boost::detail::rebind_allocator<int, Allocator>::type i_alloc;
|
typedef typename boost::detail::rebind_allocator<int, Allocator>::type i_alloc;
|
||||||
typedef typename boost::detail::rebind_allocator<iterator, Allocator>::type it_alloc;
|
typedef typename boost::detail::rebind_allocator<iterator, Allocator>::type it_alloc;
|
||||||
|
typedef typename regex_iterator_traits<iterator>::difference_type difference_type;
|
||||||
|
|
||||||
match_results_base<iterator, Allocator> temp_match;
|
match_results_base<iterator, Allocator> temp_match;
|
||||||
// failure stacks:
|
// failure stacks:
|
||||||
@ -184,9 +191,11 @@ public:
|
|||||||
jstack<int, Allocator> prev_acc;
|
jstack<int, Allocator> prev_acc;
|
||||||
int* accumulators;
|
int* accumulators;
|
||||||
unsigned int caccumulators;
|
unsigned int caccumulators;
|
||||||
|
difference_type state_count;
|
||||||
|
difference_type max_state_count;
|
||||||
iterator* loop_starts;
|
iterator* loop_starts;
|
||||||
|
|
||||||
_priv_match_data(const match_results_base<iterator, Allocator>&);
|
_priv_match_data(const match_results_base<iterator, Allocator>&, iterator, iterator, unsigned);
|
||||||
|
|
||||||
~_priv_match_data()
|
~_priv_match_data()
|
||||||
{
|
{
|
||||||
@ -202,15 +211,32 @@ public:
|
|||||||
{
|
{
|
||||||
return loop_starts;
|
return loop_starts;
|
||||||
}
|
}
|
||||||
|
void estimate_max_state_count(iterator a, iterator b, unsigned states, std::random_access_iterator_tag*)
|
||||||
|
{
|
||||||
|
difference_type dist = std::distance(a,b);
|
||||||
|
if(dist > (std::numeric_limits<difference_type>::max() / (states * 3)))
|
||||||
|
max_state_count = std::numeric_limits<difference_type>::max();
|
||||||
|
else
|
||||||
|
max_state_count = states * 3 * dist;
|
||||||
|
if(max_state_count < 1000)
|
||||||
|
max_state_count = 1000;
|
||||||
|
}
|
||||||
|
void estimate_max_state_count(iterator a, iterator b, unsigned states, void*)
|
||||||
|
{
|
||||||
|
// we don't know how long the sequence is:
|
||||||
|
max_state_count = BOOST_REGEX_MAX_STATE_COUNT;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class iterator, class Allocator>
|
template <class iterator, class Allocator>
|
||||||
_priv_match_data<iterator, Allocator>::_priv_match_data(const match_results_base<iterator, Allocator>& m)
|
_priv_match_data<iterator, Allocator>::_priv_match_data(const match_results_base<iterator, Allocator>& m, iterator a, iterator b, unsigned states)
|
||||||
: temp_match(m), matches(64, m.allocator()), prev_pos(64, m.allocator()), prev_record(64, m.allocator())
|
: temp_match(m), matches(64, m.allocator()), prev_pos(64, m.allocator()), prev_record(64, m.allocator())
|
||||||
{
|
{
|
||||||
accumulators = 0;
|
accumulators = 0;
|
||||||
caccumulators = 0;
|
caccumulators = 0;
|
||||||
loop_starts = 0;
|
loop_starts = 0;
|
||||||
|
state_count = 0;
|
||||||
|
estimate_max_state_count(a, b, states, static_cast<regex_iterator_traits<iterator>::iterator_category*>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class iterator, class Allocator>
|
template <class iterator, class Allocator>
|
||||||
@ -297,6 +323,7 @@ bool query_match_aux(iterator first,
|
|||||||
typedef typename traits::size_type traits_size_type;
|
typedef typename traits::size_type traits_size_type;
|
||||||
typedef typename traits::uchar_type traits_uchar_type;
|
typedef typename traits::uchar_type traits_uchar_type;
|
||||||
typedef typename is_byte<charT>::width_type width_type;
|
typedef typename is_byte<charT>::width_type width_type;
|
||||||
|
typedef typename re_detail::regex_iterator_traits<iterator>::difference_type difference_type;
|
||||||
|
|
||||||
// declare some local aliases to reduce pointer loads
|
// declare some local aliases to reduce pointer loads
|
||||||
// good optimising compilers should make this unnecessary!!
|
// good optimising compilers should make this unnecessary!!
|
||||||
@ -306,6 +333,7 @@ bool query_match_aux(iterator first,
|
|||||||
jstack<int, Allocator>& prev_acc = pd.prev_acc;
|
jstack<int, Allocator>& prev_acc = pd.prev_acc;
|
||||||
match_results_base<iterator, Allocator>& temp_match = pd.temp_match;
|
match_results_base<iterator, Allocator>& temp_match = pd.temp_match;
|
||||||
temp_match.set_first(first);
|
temp_match.set_first(first);
|
||||||
|
difference_type& state_count = pd.state_count;
|
||||||
|
|
||||||
const re_syntax_base* ptr = access::first(e);
|
const re_syntax_base* ptr = access::first(e);
|
||||||
bool match_found = false;
|
bool match_found = false;
|
||||||
@ -337,6 +365,7 @@ bool query_match_aux(iterator first,
|
|||||||
while(first != last)
|
while(first != last)
|
||||||
{
|
{
|
||||||
jm_assert(ptr);
|
jm_assert(ptr);
|
||||||
|
++state_count;
|
||||||
switch(ptr->type)
|
switch(ptr->type)
|
||||||
{
|
{
|
||||||
case syntax_element_match:
|
case syntax_element_match:
|
||||||
@ -816,6 +845,7 @@ bool query_match_aux(iterator first,
|
|||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
jm_assert(ptr);
|
jm_assert(ptr);
|
||||||
|
++state_count;
|
||||||
switch(ptr->type)
|
switch(ptr->type)
|
||||||
{
|
{
|
||||||
case syntax_element_match:
|
case syntax_element_match:
|
||||||
@ -929,6 +959,14 @@ bool query_match_aux(iterator first,
|
|||||||
|
|
||||||
failure:
|
failure:
|
||||||
|
|
||||||
|
//
|
||||||
|
// check to see if we've been searching too many states:
|
||||||
|
//
|
||||||
|
if(state_count >= pd.max_state_count)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Max regex search depth exceeded.");
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// check for possible partial match:
|
// check for possible partial match:
|
||||||
//
|
//
|
||||||
@ -1177,7 +1215,7 @@ unsigned int reg_grep2(Predicate foo, I first, I last, const reg_expression<char
|
|||||||
|
|
||||||
flags |= match_init;
|
flags |= match_init;
|
||||||
|
|
||||||
_priv_match_data<I, A2> pd(m);
|
_priv_match_data<I, A2> pd(m, first, last, e.size());
|
||||||
|
|
||||||
const unsigned char* _map = access::get_map(e);
|
const unsigned char* _map = access::get_map(e);
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
@ -1648,7 +1686,7 @@ bool regex_match(iterator first, iterator last, match_results<iterator, Allocato
|
|||||||
m.set_line(1, first);
|
m.set_line(1, first);
|
||||||
}
|
}
|
||||||
flags |= match_all; // must match all of input.
|
flags |= match_all; // must match all of input.
|
||||||
re_detail::_priv_match_data<iterator, Allocator> pd(m);
|
re_detail::_priv_match_data<iterator, Allocator> pd(m, first, last, e.size());
|
||||||
iterator restart;
|
iterator restart;
|
||||||
bool result = re_detail::query_match_aux(first, last, m, e, flags, pd, &restart);
|
bool result = re_detail::query_match_aux(first, last, m, e, flags, pd, &restart);
|
||||||
return result;
|
return result;
|
||||||
|
Reference in New Issue
Block a user