You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Quadratic time in find_markers (many markers) and in parsing deeply nested lists #94
Found while adapting PactTrack to 0.3.0. PactTrack validates untrusted contract text of up to 10 MiB, so superlinear paths in the validator become request-time costs. There are two paths, both measured on 0.3.0 from PyPI with time.process_time().
1. find_markers: the rest of the fragment is re-scanned for every marker
In legaldown/validator/units.pyfind_markers, each marker match computes:
This copies the rest of the fragment and runs a regex substitution over it once per marker, so the cost is O(markers × fragment length). marker_matches also tests each match against every directive (any(d.start <= match.start() < d.end for d in lexed.directives ...)), which is O(markers × directives).
The time roughly quadruples each time the input doubles.
Suggested fix:
Compute once per fragment the position from which only whitespace and comments remain. One backward pass over the comment-stripped view gives it. Then at_end becomes m.end() >= tail_start.
For the directive test, a binary search over the sorted directive starts.
PactTrack's editor also lays out a field with _layout several times per request, and 1,000 levels took about 48 s there. The cost looks like it comes from _scan_list re-scanning, and re-dedenting, each nested item's lines at every level. It may be worth either capping the nesting depth, as MAX_QUOTE_DEPTH does for quotes, or scanning each line once.
Neither of these is a correctness bug, and ordinary documents are far below these sizes. It is a denial-of-service surface for any service that validates uploaded text.
Activity