Fix RT #120600: Variable length lookbehind is not variable
Inside of study_chunk() we have to guard against infinite
recursion with recursive subpatterns. The existing logic
sort of worked, but didn't address all cases properly.
qr/
(?<W>a)
(?<BB>
(?=(?&W))(?<=(?&W))
)
(?&BB)
/x;
The pattern in the test would fail when the optimizer
was expanding (&BB). When it recursed, it creates a bitmap
for the recursion it performs, it then jumps back to
the BB node and then eventually does the first (&W) call.
At this point the bit for (&W) would be set in the bitmask.
When the recursion for the (&W) exited (fake exit through
the study frame logic) the bit was not /unset/. When the parser
then entered the (&W) again it was treated as a nested and
potentially infinite length pattern.
The fake-recursion in study-chunk made it little less obvious
what was going on in the debug output.
By reorganizing the code and adding logic to unset the bitmap
when exiting this bug was fixed. Unfortunately this also revealed
another little issue with patterns like this:
qr/x|(?0)/
qr/(x|(?1))/
which forced the creation of a new bitmask for each branch.
Effectively study_chunk treats each branch as an independent
pattern, so when we are expanding (?1) via the 'x' branch
we dont want that to prevent us from detecting the infinite recursion
in the (?1) branch. If you were to think of trips through study_chunk
as paths, and [] as recursive processing you would get something like:
BRANCH 'x' END
BRANCH (?0) [ 'x' END ]
BRANCH (?0) [ (?0) [ 'x' END ] ]
...
When we want something like:
BRANCH 'x' END
BRANCH (?0) [ 'x' END ]
BRANCH (?0) [ (?0) INFINITE_RECURSION ]
So when we deal with a branch we need to make a new recursion bitmask.