diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py index d3ff196032b3..20a602501191 100644 --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -78,6 +78,7 @@ def __init__(self): self.groupdict = {} self.groupwidths = [None] # group 0 self.lookbehindgroups = None + self.grouprefpos = {} @property def groups(self): return len(self.groupwidths) @@ -786,6 +787,10 @@ def _parse(source, state, verbose, nested, first=False): if condgroup >= MAXGROUPS: msg = "invalid group reference %d" % condgroup raise source.error(msg, len(condname) + 1) + if condgroup not in state.grouprefpos: + state.grouprefpos[condgroup] = ( + source.tell() - len(condname) - 1 + ) state.checklookbehindgroup(condgroup, source) item_yes = _parse(source, state, verbose, nested + 1) if source.match("|"): @@ -963,6 +968,11 @@ def parse(str, flags=0, state=None): assert source.next == ")" raise source.error("unbalanced parenthesis") + for g in p.state.grouprefpos: + if g >= p.state.groups: + msg = "invalid group reference %d" % g + raise error(msg, str, p.state.grouprefpos[g]) + if flags & SRE_FLAG_DEBUG: p.dump() diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 305ec8eef326..887ab781fc9d 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -575,6 +575,8 @@ def test_re_groupref_exists_errors(self): self.checkPatternError(r'()(?(1)a|b|c)', 'conditional backref with more than ' 'two branches', 10) + self.checkPatternError(r'()(?(2)a)', + "invalid group reference 2", 5) def test_re_groupref_overflow(self): from sre_constants import MAXGROUPS diff --git a/Misc/NEWS.d/next/Library/2022-04-19-17-30-17.gh-issue-91700.MRJi6m.rst b/Misc/NEWS.d/next/Library/2022-04-19-17-30-17.gh-issue-91700.MRJi6m.rst new file mode 100644 index 000000000000..73b106869697 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-19-17-30-17.gh-issue-91700.MRJi6m.rst @@ -0,0 +1,4 @@ +Compilation of regular expression containing a conditional expression +``(?(group)...)`` now raises an appropriate :exc:`re.error` if the group +number refers to not defined group. Previously an internal RuntimeError was +raised.