Skip to content

Commit a63e6f3

Browse files
authored
Fix edge-case crash in InlineProcessor
If an inlineprocessor returns an AtomicString (even though that is pointless, a plain string is atomic in that context), there can be an exception in 2 separate places. The added test case was crashing before this change.
1 parent f5b151a commit a63e6f3

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
* Remove legacy import needed only in Python 2 (#1403)
17
* Remove legacy import needed only in Python 2 (#1403)
18
* Fix typo that left the attribute `AdmonitionProcessor.content_indent` unset
18
* Fix typo that left the attribute `AdmonitionProcessor.content_indent` unset
19
(#1404)
19
(#1404)
20+
* Fix edge-case crash in `InlineProcessor` with `AtomicString` (#1406).
20
* Fix edge-case crash in `codehilite` with an empty `code` tag (#1405).
21
* Fix edge-case crash in `codehilite` with an empty `code` tag (#1405).
21
* Improve and expand type annotations in the code base (#1401).
22
* Improve and expand type annotations in the code base (#1401).
22

23

markdown/treeprocessors.py

Lines changed: 2 additions & 2 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -218,7 +218,7 @@ def linkText(text: str | None) -> None:
218
text = data[strartIndex:index]
218
text = data[strartIndex:index]
219
linkText(text)
219
linkText(text)
220

220

221-
if not isString(node): # it's Element
221+
if not isinstance(node, str): # it's Element
222
for child in [node] + list(node):
222
for child in [node] + list(node):
223
if child.tail:
223
if child.tail:
224
if child.tail.strip():
224
if child.tail.strip():
@@ -304,7 +304,7 @@ def __applyPattern(
304
if node is None:
304
if node is None:
305
return data, True, end
305
return data, True, end
306

306

307-
if not isString(node):
307+
if not isinstance(node, str):
308
if not isinstance(node.text, util.AtomicString):
308
if not isinstance(node.text, util.AtomicString):
309
# We need to process current node too
309
# We need to process current node too
310
for child in [node] + list(node):
310
for child in [node] + list(node):

tests/test_apis.py

Lines changed: 23 additions & 2 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -30,6 +30,7 @@
30
import markdown
30
import markdown
31
import warnings
31
import warnings
32
from markdown.__main__ import parse_options
32
from markdown.__main__ import parse_options
33+
from markdown import inlinepatterns
33
from logging import DEBUG, WARNING, CRITICAL
34
from logging import DEBUG, WARNING, CRITICAL
34
import yaml
35
import yaml
35
import tempfile
36
import tempfile
@@ -664,8 +665,8 @@ class testAtomicString(unittest.TestCase):
664
""" Test that `AtomicStrings` are honored (not parsed). """
665
""" Test that `AtomicStrings` are honored (not parsed). """
665

666

666
def setUp(self):
667
def setUp(self):
667-
md = markdown.Markdown()
668+
self.md = markdown.Markdown()
668-
self.inlineprocessor = md.treeprocessors['inline']
669+
self.inlineprocessor = self.md.treeprocessors['inline']
669

670

670
def testString(self):
671
def testString(self):
671
""" Test that a regular string is parsed. """
672
""" Test that a regular string is parsed. """
@@ -710,6 +711,26 @@ def testNestedAtomicString(self):
710
'*to*</span> *test*</span> *with*</p></div>'
711
'*to*</span> *test*</span> *with*</p></div>'
711
)
712
)
712

713

714+
def testInlineProcessorDoesntCrashWithWrongAtomicString(self):
715+
""" Test that an `AtomicString` returned from a Pattern doesn't cause a crash. """
716+
tree = etree.Element('div')
717+
p = etree.SubElement(tree, 'p')
718+
p.text = 'a marker c'
719+
self.md.inlinePatterns.register(
720+
_InlineProcessorThatReturnsAtomicString(r'marker', self.md), 'test', 100
721+
)
722+
new = self.inlineprocessor.run(tree)
723+
self.assertEqual(
724+
markdown.serializers.to_html_string(new),
725+
'<div><p>a &lt;b&gt;atomic&lt;/b&gt; c</p></div>'
726+
)
727+
728+
729+
class _InlineProcessorThatReturnsAtomicString(inlinepatterns.InlineProcessor):
730+
""" Return a simple text of `group(1)` of a Pattern. """
731+
def handleMatch(self, m, data):
732+
return markdown.util.AtomicString('<b>atomic</b>'), m.start(0), m.end(0)
733+
713

734

714
class TestConfigParsing(unittest.TestCase):
735
class TestConfigParsing(unittest.TestCase):
715
def assertParses(self, value, result):
736
def assertParses(self, value, result):

0 commit comments

Comments
 (0)