fix(core): escape comment markers which share characters#69829
fix(core): escape comment markers which share characters#69829arshsmith1 wants to merge 1 commit into
Conversation
|
We tried landing this in #69343. It was breaking. |
|
Yeah, and that revert was the right call. This is a different fix though, and it avoids the thing that broke. What landed in #69343 was the version with the />|->|<!--|-->|--!>|<!-$/gThat escapes a bare This PR keeps the anchors and matches the delimiter together with its context instead: /(^-?|--!?)>|<(?=!--|!-$)/gThe accepted language is unchanged, so non-overlapping text comes out byte-identical. Running both against every case already in
So: zero pre-existing cases change output here (the reverted one changed four), and the overlap is still closed. All 16 existing Worth saying the anchored regex was never the bug. The bug is only that Happy to run it through a TGP if that helps derisk it. |
|
Can we add to the tests the cases that were broken in the previous PR ? I'll run this change through a TGP to confirm we're good this time. |
escapeCommentText matched each disallowed marker as a whole, so a marker that overlaps an already matched one was skipped by the scanner and left unescaped. Match the delimiter together with its context instead, which keeps the matched language identical for the existing cases.
1cfe73f to
59b4171
Compare
|
Added those. New |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: N/A
escapeCommentTextmatches each disallowed marker as a whole with a single global regex. SinceString.replacewith/gmoveslastIndexpast each match, a marker that overlaps one already consumed is never seen, and its delimiters stay unescaped.<!--!>is the shortest case: the scanner takes<!--at offset 0 and resumes at offset 4, so the--!>sitting at offset 2 (it shares the--) is skipped. Only the leading<gets wrapped:Walking the tokenizer over
<!--+<!--!><img src=x onerror=alert(1)>+-->, the!>puts it in comment-end-bang and then back to the data state, so the comment closes early and the<img>after it parses as a live element. That is the round-trip the docstring on this function says it protects.The existing spec covers each marker on its own (
'>','->','<!--','-->','--!>','<!-') but never two that share characters, which is why this slipped through.What is the new behavior?
The pattern matches the
</>delimiter along with its surrounding context rather than the whole marker, so nothing a later marker needs is consumed and overlapping markers are all escaped:The accepted language is unchanged, so output for every case already in
dom_spec.tsis byte-identical, including the ones that must stay untouched (.>,.->,<!-.). The three new expectations fail onmainand pass here.Does this PR introduce a breaking change?
Other information
The reachable call site today is the
ngReflectbinding comment inshared.ts, which is dev-mode and opt-in, so the live blast radius is small. Fixing it inescapeCommentTextanyway since the escaping contract is what the rest of the comment-node path relies on.