Skip to content

Commit 297e873

Browse files
committed
Fix for bug in recursive expressions, see http://lists.boost.org/Archives/boost/2015/03/221018.php
1 parent 74d6318 commit 297e873

File tree

4 files changed

+32
-13
lines changed

4 files changed

+32
-13
lines changed

include/boost/regex/v4/perl_matcher.hpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,23 +253,40 @@ class repeater_count
253253
int state_id;
254254
std::size_t count; // the number of iterations so far
255255
BidiIterator start_pos; // where the last repeat started
256+
257+
repeater_count* unwind_until(int n, repeater_count* p, int current_recursion_id)
258+
{
259+
while(p && (p->state_id != n))
260+
{
261+
if(-2 - current_recursion_id == p->state_id)
262+
return 0;
263+
p = p->next;
264+
if(p && (p->state_id < 0))
265+
{
266+
p = unwind_until(p->state_id, p, current_recursion_id);
267+
if(!p)
268+
return p;
269+
p = p->next;
270+
}
271+
}
272+
return p;
273+
}
256274
public:
257275
repeater_count(repeater_count** s) : stack(s), next(0), state_id(-1), count(0), start_pos() {}
258-
259-
repeater_count(int i, repeater_count** s, BidiIterator start)
276+
277+
repeater_count(int i, repeater_count** s, BidiIterator start, int current_recursion_id)
260278
: start_pos(start)
261279
{
262280
state_id = i;
263281
stack = s;
264282
next = *stack;
265283
*stack = this;
266-
if(state_id > next->state_id)
284+
if((state_id > next->state_id) && (next->state_id >= 0))
267285
count = 0;
268286
else
269287
{
270288
repeater_count* p = next;
271-
while(p && (p->state_id != state_id))
272-
p = p->next;
289+
p = unwind_until(state_id, p, current_recursion_id);
273290
if(p)
274291
{
275292
count = p->count;

include/boost/regex/v4/perl_matcher_non_recursive.hpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ template <class BidiIterator>
8787
struct saved_repeater : public saved_state
8888
{
8989
repeater_count<BidiIterator> count;
90-
saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start)
91-
: saved_state(saved_state_repeater_count), count(i,s,start){}
90+
saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start, int current_recursion_id)
91+
: saved_state(saved_state_repeater_count), count(i, s, start, current_recursion_id){}
9292
};
9393

9494
struct saved_extra_block : public saved_state
@@ -309,7 +309,7 @@ inline void perl_matcher<BidiIterator, Allocator, traits>::push_repeater_count(i
309309
pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
310310
--pmp;
311311
}
312-
(void) new (pmp)saved_repeater<BidiIterator>(i, s, position);
312+
(void) new (pmp)saved_repeater<BidiIterator>(i, s, position, this->recursion_stack.size() ? this->recursion_stack.back().idx : (INT_MIN + 3));
313313
m_backup_state = pmp;
314314
}
315315

@@ -923,12 +923,12 @@ bool perl_matcher<BidiIterator, Allocator, traits>::match_recursion()
923923
recursion_stack.push_back(recursion_info<results_type>());
924924
recursion_stack.back().preturn_address = pstate->next.p;
925925
recursion_stack.back().results = *m_presult;
926-
if(static_cast<const re_recurse*>(pstate)->state_id > 0)
927-
{
928-
push_repeater_count(static_cast<const re_recurse*>(pstate)->state_id, &next_count);
929-
}
930926
pstate = static_cast<const re_jump*>(pstate)->alt.p;
931927
recursion_stack.back().idx = static_cast<const re_brace*>(pstate)->index;
928+
//if(static_cast<const re_recurse*>(pstate)->state_id > 0)
929+
{
930+
push_repeater_count(-(2 + static_cast<const re_brace*>(pstate)->index), &next_count);
931+
}
932932

933933
return true;
934934
}
@@ -952,6 +952,7 @@ bool perl_matcher<BidiIterator, Allocator, traits>::match_endmark()
952952
*m_presult = recursion_stack.back().results;
953953
push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, &recursion_stack.back().results);
954954
recursion_stack.pop_back();
955+
push_repeater_count(-(2 + index), &next_count);
955956
}
956957
}
957958
}

include/boost/regex/v4/perl_matcher_recursive.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ bool perl_matcher<BidiIterator, Allocator, traits>::match_rep()
308308
// Always copy the repeat count, so that the state is restored
309309
// when we exit this scope:
310310
//
311-
repeater_count<BidiIterator> r(rep->state_id, &next_count, position);
311+
repeater_count<BidiIterator> r(rep->state_id, &next_count, position, this->recursion_stack.size() ? this->recursion_stack.back().idx : INT_MIN + 3);
312312
//
313313
// If we've had at least one repeat already, and the last one
314314
// matched the NULL string then set the repeat count to

test/regress/test_perl_ex.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ void test_recursion()
918918
TEST_REGEX_SEARCH("namespace\\s+(\\w+)\\s+(\\{(?:[^{}]*(?:(?2)[^{}]*)*)?\\})", perl, "namespace one { namespace two { int foo(); } }", match_default, make_array(0, 46, 10, 13, 14, 46, -2, -2));
919919
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));
920920
TEST_INVALID_REGEX("((?1)|a)", perl);
921+
TEST_REGEX_SEARCH("a(?0)?", perl, "aaaaa", match_default, make_array(0, 5, -2, -2));
921922

922923
// Recursion to a named sub with a name that is used multiple times:
923924
TEST_REGEX_SEARCH("(?:(?<A>a+)|(?<A>b+))\\.(?&A)", perl, "aaaa.aa", match_default, make_array(0, 7, 0, 4, -1, -1, -2, -2));

0 commit comments

Comments
 (0)