diff --git a/CHANGES.md b/CHANGES.md index 4cd67e57..de7d1b65 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 #736] Clarify how to enable file variables in the Python API and command-line help (#269, #365). - [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|`. diff --git a/lib/markdown2.py b/lib/markdown2.py index 8f0e0a6d..a31647c1 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -1169,7 +1169,20 @@ 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): + # find all open tags on each line. Tags split over multiple lines are + # ignored, as with the original regex. Stopping at the first + # unclosed ', pos) + if end == -1: + break + open_count += 1 + pos = line.find(open_tag, end + 1) + if open_count != text.count('' % tag_name): return False # check that close tag position is AFTER open tag @@ -1347,8 +1360,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 '