122 lines
5.2 KiB
Markdown
122 lines
5.2 KiB
Markdown
# Performance and risk analysis
|
|
|
|
Regex Tools provides one deliberately scoped analysis implementation:
|
|
ECMAScript 2025 patterns parsed into the application-owned normalized AST and
|
|
executed by the browser's native `RegExp` runtime. The analyser does not apply
|
|
ECMAScript findings to PCRE2, Python, Java or any other flavour.
|
|
|
|
Analysis is advisory. The UI uses “potential risk”, “possibly” and “observed
|
|
under selected limits”. It never turns an empty finding list into “safe”,
|
|
“guaranteed linear” or a vulnerability proof.
|
|
|
|
## Static analysis
|
|
|
|
The application-owned `regex-tools-ecmascript-heuristics` analyser walks at
|
|
most 20,000 normalized nodes and returns at most 100 findings. Each finding
|
|
contains:
|
|
|
|
- flavour and UTF-16 source range;
|
|
- stable rule identifier;
|
|
- static or dynamically observed provenance;
|
|
- explanation and example risk;
|
|
- low, medium or high confidence;
|
|
- limitations;
|
|
- a suggested investigation.
|
|
|
|
The current rules review nested and nullable repetition, ambiguous repeated
|
|
alternatives, overlapping alternative prefixes, wildcards and backreferences
|
|
inside repetition, repeated lookaround bodies, unanchored amplification,
|
|
capture count, nesting depth and replacement-output expansion. These are
|
|
structural heuristics. They do not model the native engine's complete compiled
|
|
program, optimizations or calling context.
|
|
|
|
## Dynamic growth probes
|
|
|
|
The user defines a bounded subject family:
|
|
|
|
```text
|
|
prefix + repeatedFragment.repeat(repetitions) + suffix
|
|
```
|
|
|
|
The byte and UTF-16 size are calculated before the generated string is
|
|
allocated. The repeated fragment is limited to 4,096 UTF-16 units, each affix
|
|
to 16,384 units, the run to 24 samples, and repetitions to 10,000,000. The UI
|
|
defaults to a 1 MiB generated-subject cap even though the central interactive
|
|
hard cap remains 16 MiB.
|
|
|
|
Every probe executes in a dedicated worker. The supervisor terminates and
|
|
discards that worker on per-sample timeout, cancellation or crash. Runs also
|
|
stop at:
|
|
|
|
- the selected repetition bound;
|
|
- the selected generated-byte bound;
|
|
- the selected step bound;
|
|
- the 30-second aggregate wall bound;
|
|
- a selected normalized-growth threshold.
|
|
|
|
The growth threshold compares the time ratio with the input-size ratio for two
|
|
adjacent samples. Sub-millisecond measurements below a noise floor do not
|
|
trigger it. A threshold observation characterizes only those generated inputs
|
|
and that browser. Timeout, crash, compile rejection and non-match remain
|
|
distinct states.
|
|
|
|
The UI renders time and outcome in separate plots and keeps the exact sample
|
|
table alongside them.
|
|
|
|
## Benchmark method
|
|
|
|
A benchmark begins with a fresh analysis worker. Worker creation and its
|
|
identity response form the separate cold-start measurement. The first native
|
|
engine use is retained as a cold sample. Configured warm-up samples are
|
|
discarded; configured measured samples produce the warm statistics.
|
|
|
|
Each sample measures these phases separately:
|
|
|
|
- `RegExp` construction;
|
|
- first `exec`;
|
|
- bounded all-match iteration;
|
|
- native string replacement when its conservative output bound is acceptable;
|
|
- all-match throughput and match count.
|
|
|
|
All-match iteration retains only counts, not values or captures. It follows the
|
|
same explicit scan-all, global, sticky and Unicode zero-length advancement
|
|
semantics as the workbench. The application-added indices flag remains in the
|
|
effective flags so the measured operation reflects interactive execution.
|
|
|
|
Replacement timing is skipped when match collection reaches its bound or a
|
|
conservative estimate can exceed 8 Mi UTF-16 units. This prevents a benchmark
|
|
from using an unbounded native replacement merely to obtain a timing.
|
|
It is also skipped for explicit scan-all with sticky `y`: native
|
|
`String.replace` processes only one sticky match, while the workbench's
|
|
explicit scan-all operation can process a contiguous sequence. Reporting that
|
|
different operation as the same benchmark would be misleading.
|
|
|
|
Warm metrics include sample count, minimum, conventional median, nearest-rank
|
|
p95 and maximum. Milliseconds are shown to two decimal places, with values
|
|
below 0.01 ms labelled accordingly; this does not imply nanosecond accuracy.
|
|
The result retains subject size, match count, effective flags, browser runtime
|
|
identity and engine identity.
|
|
|
|
Defaults:
|
|
|
|
| Setting | Default | Hard bound |
|
|
| ----------------------- | ------: | ---------: |
|
|
| Warm-up samples | 3 | 100 |
|
|
| Measured samples | 15 | 1,000 |
|
|
| Per-sample timeout | 2 s | 10 s |
|
|
| Aggregate wall time | 30 s | 30 s |
|
|
| Matches per sample | 10,000 | 10,000 |
|
|
| Replacement output gate | 8 MiU | 8 MiU |
|
|
|
|
One subject is not a complete performance characterization. Results from
|
|
different algorithms, pattern ports, browser engines, WebAssembly runtimes or
|
|
machines are not directly comparable. Trace-enabled execution is never used
|
|
for benchmark results.
|
|
|
|
## Privacy and persistence
|
|
|
|
Patterns, subjects, generated inputs, findings and benchmark samples remain in
|
|
the browser. No analysis request is uploaded. Analysis settings and results are
|
|
currently ephemeral and are not added to project JSON or IndexedDB; this also
|
|
keeps large benchmark subjects out of persisted projects by default.
|