PureXML/Sources
Mihaela Mihaljevic b05b428e30
perf(parsing): linearize entity-graph checks for billion-laughs (#342)
* perf(parsing): memoize the markup-producing entity check (billion-laughs)

splitAtMarkupEntity / producesMarkup recursed into every reference of
every replacement with no memoization, so a nested entity chain was
traversed O(references^depth) times: a classic eight-level billion-laughs
took ~18s of CPU to reject. The check is now memoized per entity name (the
property depends only on the fixed entity graph), so it is O(entities). The
same document now rejects in ~0.6s, bounded by the expansion budget. No
change to which documents are accepted; cyclic entities still rejected.
Found by adversarial probing; closes the no-markup case of #339.

* perf(parsing): three-colour DFS for the No-Recursion check

checkRecursion validated the entity reference graph with only an
in-progress (grey) set and no record of fully-verified entities, so a
billion-laughs graph was re-walked O(references^depth) times: a
markup-producing eight-level document took ~31s to reject. It is now a
three-colour DFS: an entity is added to a black set only after its whole
reachable subgraph returns acyclic, so it can never reach a chain node
that reaches it, and skipping it on revisit is sound. The walk becomes one
pass over the distinct edges (~31s -> ~11s for that document). Cyclic
entities are still rejected; no accepted document changes. Part of #339.
2026-06-26 15:30:51 +02:00
..
Canonical feat(canonical): C14N 1.0 spec-example vectors, three conformance fixes 2026-06-10 08:51:47 +02:00
Catalog feat(catalog): honor group-level prefer override 2026-06-08 18:05:03 +02:00
Emitting perf(serialize): scan bytes, not graphemes, to find characters to escape (#297) 2026-06-25 15:39:20 +02:00
HTML fix(html): percent-escape non-ASCII characters in URI-valued attributes (closes output32) (#263) 2026-06-24 03:27:49 +02:00
Model perf(parse): adopt prepared children when materializing the tree (#293) 2026-06-25 13:02:20 +02:00
Parsing perf(parsing): linearize entity-graph checks for billion-laughs (#342) 2026-06-26 15:30:51 +02:00
Pattern feat(pattern): streaming xmlPattern matching 2026-06-08 05:49:13 +02:00
Regex docs(schema): disclose the contested-corpus basis for rejecting unescaped [ (#250) 2026-06-23 03:34:38 +02:00
Schema refactor: remove three more dead functions (#331) 2026-06-26 12:41:34 +02:00
Stream chore: scaffold PureXML pure-Swift XML package 2026-06-07 23:20:20 +02:00
Validation feat(schema): locate compile diagnostics with validation coding paths (#169) 2026-06-16 10:26:11 +02:00
XInclude feat(xinclude): range inclusion via XPointer range model (#87) 2026-06-09 04:19:38 +02:00
XPath refactor: remove three dead file-scoped functions (#330) 2026-06-26 12:04:07 +02:00
XPointer perf(xpointer): linear-time string-range() search (#314) 2026-06-26 04:01:41 +02:00
XSLT refactor: remove three more dead functions (#331) 2026-06-26 12:41:34 +02:00
API.swift perf(parse): build the TreeNode tree directly from the event stream (#295) 2026-06-25 14:15:57 +02:00
Lint.swift feat(editor): unified lint surface merging parse and validation diagnostics 2026-06-08 13:18:29 +02:00
PureXML.swift feat(html): lenient HTML parser and serializer 2026-06-08 07:12:42 +02:00
QuickFix.swift feat(editor): structured quick-fixes from completions 2026-06-08 13:35:33 +02:00