Open Bug 2018839 Opened 8 months ago Updated 7 months ago

Range.deleteContents() and extractContents() collapse range after mutations, can produce invalid position

Categories

(Core :: DOM: Core & HTML, defect)

defect

Tracking

()

People

(Reporter: steven, Unassigned, NeedInfo)

Details

Attachments

(1 file)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36

Steps to reproduce:

  1. Create a Range spanning multiple child nodes of a container element
  2. Call range.deleteContents() or range.extractContents()
  3. Inspect the range's startContainer, startOffset, endContainer, endOffset

The DOM spec computes the collapse target (newNode, newOffset) before mutations but applies it after — at which point script running during remove (via "removing steps" hooks) could have modified the DOM, making those pre-computed values point to an invalid position.

Repro HTML attached. (All current browsers pass the conformance tests today because no removing step currently fires synchronous script, but the code path is latently incorrect.)

Spec issue: https://github.com/whatwg/dom/issues/1446
Chromium bug: https://issues.chromium.org/issues/486922855

Actual results:

The range collapse step runs after all DOM mutations. If a removing step were to fire synchronous script that modifies the DOM, the pre-computed (newNode, newOffset) could reference an invalid position — a detached node or an offset beyond the node's child count.

Expected results:

The range should be collapsed to (newNode, newOffset) before mutations begin. The DOM's built-in live range maintenance mechanisms (live range pre-remove steps and replace data range adjustments) will then automatically keep the range valid through subsequent operations.

Has STR: --- → yes

:smaug can you double-check that the spec change looks correct?

Severity: -- → S3
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(smaug)

Follow-up from empirical testing (whatwg/dom#1452 comment):

My original "latent bug" characterization was based on a mistaken assumption that no
removing step currently fires synchronous script. That was wrong. Firefox 135 already
produces startOffset: 0 (collapse-before-mutations) when a disconnectedCallback
or iframe pagehide/unload removes a sibling node mid-operation.

Worth noting: pagehide and unload fired synchronously during iframe removal in
Firefox 135 in my test — this was unexpected given Bugzilla #1850228. That separate
bug may describe a different scenario, or behavior may have changed since it was filed.

The spec change (whatwg/dom#1452) is a clarification aligning the algorithm with
existing browser behavior, not a fix for a shipping bug. I apologize for the noise.
Please close as appropriate.

Test output and results: https://github.com/whatwg/dom/pull/1452#issuecomment-4012955171

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: