diff --git a/CHANGES.md b/CHANGES.md index 8911b5cb..2077c78b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## python-markdown2 2.5.6 (not yet released) +- [pull #732] Fix excessive CPU use in the inline HTML tokenizer on repeated unclosed tag fragments (#707) - [pull #730] Fix `tables` extra splitting multi-backtick code spans at a leading pipe and merging cells after a code span containing literal backticks. - [pull #729] Fix `tables` extra merging cells when a pipe directly follows a code span, as in compact rows like `|`-v`|verbose|`. - [pull #725] Fix `tables` extra dropping escaped pipes at the end of header and body rows. diff --git a/lib/markdown2.py b/lib/markdown2.py index b3c29847..fe726298 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -1171,7 +1171,24 @@ def _tag_is_closed(self, tag_name: str, text: str) -> bool: return True # check if number of open tags == number of close tags - if len(re.findall('<%s(?:.*?)>' % tag_name, text)) != text.count('' % tag_name): + # (a linear scan: `` re-scans the rest of the line from every + # unclosed ` line_end: + line_end = text.find('\n', pos) + if line_end == -1: + line_end = len(text) + end = text.find('>', pos, line_end) + if end == -1: + pos = text.find(open_tag, line_end + 1) + else: + open_count += 1 + pos = text.find(open_tag, end + 1) + if open_count != text.count('' % tag_name): return False # check that close tag position is AFTER open tag @@ -1349,8 +1366,7 @@ def _run_span_gamut(self, text: str) -> str: (?:\w+) # tag name (?: # attributes \s+ # whitespace after tag - (?:[^\t<>"'=/]+:)? - [^<>"'=/]+= # attr name + [^\s<>"'=/][^<>"'=/]*= # attr name, can't start with whitespace (?:"[^"]*?"|'[^']*?'|[^<>"'=/\s]+) # value, quoted or unquoted. If unquoted, no spaces allowed )* \s*/?> diff --git a/test/test_redos.py b/test/test_redos.py index 3bea176f..2951ac2d 100644 --- a/test/test_redos.py +++ b/test/test_redos.py @@ -43,6 +43,21 @@ def issue_668(): return 'a_b **x***y* c_d' +def issue_707_unclosed_tags(): + # https://github.com/trentm/python-markdown2/issues/707 + return '