From b3fa6ed5176fc220e3ee4b9a5c006c70ccbf5206 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Fri, 8 Aug 2025 19:05:01 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=8C=20limit=20the=20number=20of=20auto?= =?UTF-8?q?completed=20cells=20in=20a=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements: https://github.com/markdown-it/markdown-it/commit/00b8a93c8fe60d66e862445082b61d1ce1abae1c --- markdown_it/rules_block/table.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/markdown_it/rules_block/table.py b/markdown_it/rules_block/table.py index 4b666c1d..c52553d8 100644 --- a/markdown_it/rules_block/table.py +++ b/markdown_it/rules_block/table.py @@ -9,6 +9,13 @@ headerLineRe = re.compile(r"^:?-+:?$") enclosingPipesRe = re.compile(r"^\||\|$") +# Limit the amount of empty autocompleted cells in a table, +# see https://github.com/markdown-it/markdown-it/issues/1000, +# Both pulldown-cmark and commonmark-hs limit the number of cells this way to ~200k. +# We set it to 65k, which can expand user input by a factor of x370 +# (256x256 square is 1.8kB expanded into 650kB). +MAX_AUTOCOMPLETED_CELLS = 0x10000 + def getLine(state: StateBlock, line: int) -> str: pos = state.bMarks[line] + state.tShift[line] @@ -172,6 +179,7 @@ def table(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool token = state.push("tr_close", "tr", -1) token = state.push("thead_close", "thead", -1) + autocompleted_cells = 0 nextLine = startLine + 2 while nextLine < endLine: if state.sCount[nextLine] < state.blkIndent: @@ -196,6 +204,12 @@ def table(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool if columns and columns[-1] == "": columns.pop() + # note: autocomplete count can be negative if user specifies more columns than header, + # but that does not affect intended use (which is limiting expansion) + autocompleted_cells += columnCount - len(columns) + if autocompleted_cells > MAX_AUTOCOMPLETED_CELLS: + break + if nextLine == startLine + 2: token = state.push("tbody_open", "tbody", 1) token.map = tbodyLines = [startLine + 2, 0]