Skip to content

fix: avoid quadratic inline footnote membership checks - #478

Open
susyimes wants to merge 4 commits into
lepture:mainfrom
susyimes:blackhole/footnote-defs-membership-quadratic
Open

fix: avoid quadratic inline footnote membership checks#478
susyimes wants to merge 4 commits into
lepture:mainfrom
susyimes:blackhole/footnote-defs-membership-quadratic

Conversation

@susyimes

@susyimes susyimes commented Aug 9, 2026

Copy link
Copy Markdown

Summary

Inline footnote parsing already maintained a footnote_indexes mapping, but still checked key not in notes. That scanned a growing list for every new reference and made documents with many distinct footnotes quadratic.

This PR:

  • uses the existing index mapping for O(1) membership checks;
  • preserves the ordered footnotes list and rendered numbering;
  • adds a deterministic regression test that fails if the parser falls back to list membership.

Regression coverage

tests/test_security_footnotes.py supplies a list whose __contains__ raises. The patched implementation passes because it checks footnote_indexes; temporarily restoring the old key not in notes line makes the test fail at that exact membership operation.

This replaces the former wall-clock doubling-ladder test, which could false-positive under host load.

Verification

  • uv run --locked --group lint ruff check . — passed
  • uv run --locked --group lint mypy — passed, 38 source files
  • Python 3.13.13: uv run --locked --group test pytest --cov=mistune --cov-branch --cov-report=xml — 766 passed
  • Python 3.14.3: the same test command in an isolated uv environment — 766 passed

Provenance and sealed evidence

This contribution was originally prepared by blackhole-agent and was amended after review feedback. The evidence below was regenerated after synchronizing with upstream main and matches the reopened PR exactly.

  • upstream base: a1b50bc12e066e5707ff797f821829bfcdab03b5
  • PR head: 019af68ae9847f7adebc07a12fb762c9d50a0baa
  • Git tree: e8ae33bfda9f74f623dead368778d23c83d731fa
  • PR diff SHA256: 25e0875d9ae6c3b31f6622ca4373ba290d1c2ec067b557558d29411329e7af26
  • src/mistune/plugins/footnotes.py blob SHA256: 3f1229e3a3fe221dd1038a765184d1626559bbd78acdab40d4845f721b96b474
  • tests/test_security_footnotes.py blob SHA256: 790d457821de4913e6b95b7755ab65b4875983c92ce2a9da9bb5bca45919bcfc

The PR diff digest is the SHA256 of GitHub's application/vnd.github.diff response for PR #478; it matches the locally generated base-to-head diff byte-for-byte.

Inline footnote parsing does O(n) list membership per reference (quadratic DoS on n footnote references)

Defect id: footnote-defs-membership-quadratic
Verified against upstream tag v3.3.4 and HEAD (triage: unfixed_at_head).

Generated-by: blackhole-agent upstream-publication plane (autonomous stewardship mission)
Copilot AI lite review requested due to automatic review settings August 9, 2026 11:04
susyimes pushed a commit to susyimes/blackhole-agent that referenced this pull request Aug 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a potential algorithmic complexity DoS in the footnotes plugin by eliminating repeated O(n) list membership checks during inline footnote reference parsing, and adds a regression test/repro to prevent reintroduction.

Changes:

  • Optimize parse_inline_footnote to use a dict (footnote_indexes) for O(1) membership checks instead of scanning the footnotes list.
  • Add a standalone complexity repro script and a regression test that runs it.
  • Extend the test suite with a performance-focused guard against superlinear behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/mistune/plugins/footnotes.py Switch inline footnote membership checks from list to dict index to avoid quadratic behavior.
tests/footnote_defs_quadratic.py Add standalone doubling-ladder repro to detect superlinear growth.
tests/test_contribution_footnote_defs_membership_quadratic.py Add pytest regression test that executes the repro against the local src tree.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/test_contribution_footnote_defs_membership_quadratic.py Outdated
Comment thread tests/footnote_defs_quadratic.py Outdated
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.86%. Comparing base (a1b50bc) to head (019af68).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #478   +/-   ##
=======================================
  Coverage   90.86%   90.86%           
=======================================
  Files          36       36           
  Lines        3713     3713           
  Branches      696      696           
=======================================
  Hits         3374     3374           
  Misses        208      208           
  Partials      131      131           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@susyimes susyimes closed this Aug 31, 2026
@susyimes susyimes changed the title fix: Inline footnote parsing does O fix: avoid quadratic inline footnote membership checks Aug 31, 2026
@susyimes susyimes reopened this Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants