Skip to content

fix: bound active formatting element reconstruction - #53

Open
Adyej999 wants to merge 1 commit into
angular:mainfrom
Adyej999:fix/active-formatting-reconstruction-budget
Open

Adyej999 wants to merge 1 commit into
angular:mainfrom
Adyej999:fix/active-formatting-reconstruction-budget

Conversation

@Adyej999

@Adyej999 Adyej999 commented Sep 24, 2026 •

Copy link
Copy Markdown

Summary

Bounds active formatting element reconstruction work during HTML parsing to prevent pathological mis-nested formatting markup from causing super-linear DOM growth and exhausting the Node.js heap.

This affects DOMino's HTML parsing path used by Angular server-side rendering.

Problem

When formatting elements are repeatedly left in the active formatting elements list, afereconstruct() can reconstruct an increasingly large number of stale entries.

A comparatively small input can therefore cause quadratic DOM allocation.

On current main, using Node.js 22.22.3 with a 128 MiB heap limit, an 8,290-byte non-numeric test case causes the unpatched parser to terminate with a fatal V8 out-of-memory error (SIGABRT).

This remains reproducible after the existing numeric attribute storage hardening (c5aa1eb). The reproducer uses non-numeric attribute names, so the active-formatting reconstruction issue does not depend on sparse numeric attribute storage.

Fix

Track:

  • the amount of input supplied to the parser;
  • the cumulative number of active formatting element reconstructions.

Reconstruction work is bounded to:

max(4096, inputLength * 2)

If this limit is exceeded, parsing stops with a controlled error instead of continuing until the process exhausts its heap.

The accounting also handles incremental parsing: buffered input is counted when originally supplied, while process() and resume() re-enter the parser with an empty string and do not count the same input again.

Compatibility

The existing DOMino test corpus was also tested with substantially stricter experimental budgets.

All existing tests still passed with:

max(256, inputLength)
max(512, inputLength)
max(1024, inputLength)
max(2048, inputLength)

The submitted max(4096, inputLength * 2) limit therefore provides additional compatibility headroom.

Incremental parsing was additionally checked using chunk sizes of:

1, 2, 7, 16, 64, 256, and 4096 bytes

The pathological input was bounded in every case, while normally nested formatting continued to parse successfully.

Tests

Added regression coverage for:

  • bounding pathological active formatting reconstruction;
  • preserving normally nested formatting-element parsing.

The pathological regression fails before the fix with a missing expected exception and passes after applying the fix.

Full test suite on current main with the patch:

2238 passing

fixes : angular/angular#70926

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.

Angular SSR: Domino active formatting reconstruction can cause heap exhaustion

1 participant