Skip to content

script: Use is_in_a_document_tree() to check if a node is in a tree - #46866

Merged
mrobinson merged 1 commit into
servo:mainfrom
SimonSapin:compare_dom_tree_position-assertion
Jul 30, 2026
Merged

script: Use is_in_a_document_tree() to check if a node is in a tree#46866
mrobinson merged 1 commit into
servo:mainfrom
SimonSapin:compare_dom_tree_position-assertion

Conversation

@SimonSapin

@SimonSapin SimonSapin commented Jul 29, 2026

Copy link
Copy Markdown
Member

… instead of .has_parent(). Being in a tree is a pre-condition of insert_pre_order() for its call to compare_dom_tree_position(). Failing to uphold that pre-condition caused a panic in some case found by a DOM fuzzer.

Fixes: #46790
Testing: adding a new crashtest to WPT, manually checked to crash before the code change

… instead of `.has_parent()`. Being in a tree is a pre-condition of
`insert_pre_order()` for its call to `compare_dom_tree_position()`.
Failing to uphold that pre-condition caused a panic in some case
found by a DOM fuzzer.

Fixes: servo#46790
Testing: adding a new crashtest to WPT

Signed-off-by: Simon Sapin <simon@igalia.com>
@SimonSapin
SimonSapin requested a review from gterzian as a code owner July 29, 2026 17:18
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Jul 29, 2026
@SimonSapin SimonSapin added the T-linux-wpt Do a try run of the WPT label Jul 29, 2026
@github-actions github-actions Bot removed the T-linux-wpt Do a try run of the WPT label Jul 29, 2026
@github-actions

Copy link
Copy Markdown

🔨 Triggering try run (#30474743087) for Linux (WPT)

@servo-wpt-sync

Copy link
Copy Markdown
Collaborator

🤖 Opened new upstream WPT pull request (web-platform-tests/wpt#61611) with upstreamable changes.

@servo-wpt-sync

Copy link
Copy Markdown
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#61611) title and body.

@github-actions

Copy link
Copy Markdown

Test results for linux-wpt from try job (#30474743087):

Flaky unexpected result (46)
  • OK /_webgl/conformance/textures/misc/texture-upload-size.html (#21770)
    • FAIL [expected PASS] subtest: WebGL test #45

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #47

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #49

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #51

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • PASS [expected FAIL] subtest: WebGL test #53
    • PASS [expected FAIL] subtest: WebGL test #55
    • PASS [expected FAIL] subtest: WebGL test #57
    • PASS [expected FAIL] subtest: WebGL test #59
    • FAIL [expected PASS] subtest: WebGL test #61

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #63

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • And 6 more unexpected results...
  • CRASH [expected OK] /_webgl/conformance/uniforms/no-over-optimization-on-uniform-array-06.html
  • CRASH [expected OK] /_webgl/conformance/uniforms/no-over-optimization-on-uniform-array-14.html
  • TIMEOUT [expected OK] /_webgl/conformance/uniforms/no-over-optimization-on-uniform-array-16.html
    • NOTRUN [expected PASS] subtest: Overall test
  • TIMEOUT [expected OK] /_webgl/conformance2/state/gl-object-get-calls.html
    • NOTRUN [expected PASS] subtest: Overall test
  • CRASH [expected OK] /_webgl/conformance2/wasm/readpixels-2gb-in-4gb-wasm-memory.html
  • OK /cookies/partitioned-cookies/partitioned-cookies-samesite-attribute.https.html (#45255)
    • FAIL [expected PASS] subtest: In embedded cross-site contexts, partitioned cookies can only be set with explicit SameSite=None

      assert_equals: expected 0 but got 3
      

  • FAIL [expected PASS] /css/css-backgrounds/background-size-042.html
  • OK /css/css-fonts/variations/at-font-face-font-matching.html (#20684)
    • FAIL [expected PASS] subtest: Matching font-weight: '500' should prefer '351 398' over '501 550'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

    • FAIL [expected PASS] subtest: Matching font-style: 'oblique 20deg' should prefer 'oblique 10deg' over 'oblique 0deg'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

    • FAIL [expected PASS] subtest: Matching font-style: 'oblique 21deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

    • PASS [expected FAIL] subtest: Matching font-style: 'oblique 21deg' should prefer 'oblique -40deg -30deg' over 'italic'
  • FAIL [expected PASS] /css/css-sizing/dynamic-available-size-iframe.html (#45763)
  • CRASH [expected OK] /dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html
  • TIMEOUT [expected CRASH] /editing/whitespaces/chrome-compat/inserttext.tentative.html
  • TIMEOUT [expected OK] /fetch/content-encoding/br/big-br-body.https.any.html
    • TIMEOUT [expected PASS] subtest: large br data should be decompressed successfully

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: large br data should be decompressed successfully with byte stream
  • TIMEOUT [expected OK] /fetch/content-encoding/br/big-br-body.https.any.worker.html
    • TIMEOUT [expected PASS] subtest: large br data should be decompressed successfully

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: large br data should be decompressed successfully with byte stream
  • TIMEOUT [expected OK] /fetch/content-encoding/gzip/big-gzip-body.https.any.worker.html
    • TIMEOUT [expected PASS] subtest: large gzip data should be decompressed successfully

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: large gzip data should be decompressed successfully with byte stream
  • TIMEOUT [expected OK] /fetch/content-encoding/zstd/big-zstd-body.https.any.html
    • TIMEOUT [expected PASS] subtest: large zstd data should be decompressed successfully

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: large zstd data should be decompressed successfully with byte stream
  • TIMEOUT [expected OK] /fetch/content-encoding/zstd/big-zstd-body.https.any.worker.html
    • TIMEOUT [expected PASS] subtest: large zstd data should be decompressed successfully

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: large zstd data should be decompressed successfully with byte stream
  • OK [expected ERROR] /fetch/fetch-later/quota/same-origin-iframe/sandboxed-iframe.https.window.html (#41704)
  • OK [expected TIMEOUT] /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-submit-button-click.html (#44099)
    • FAIL [expected TIMEOUT] subtest: Replace before load, triggered by submitButton.click()

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?thereplacement=" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/resources/code-injector.html?pipe=sub(none)&amp;code=%0A%20%20%20%20const%20form%20%3D%20document.createElement(%22form%22)%3B%0A%20%20%20%20form.action%20%3D%20%22%2Fcommon%2Fblank.html%22%3B%0A%0A%20%20%20%20const%20input%20%3D%20document.createElement(%22input%22)%3B%0A%20%20%20%20input.type%20%3D%20%22hidden%22%3B%0A%20%20%20%20input.name%20%3D%20%22thereplacement%22%3B%0A%20%20%20%20form.append(input)%3B%0A%0A%20%20%20%20const%20button%20%3D%20document.createElement(%22button%22)%3B%0A%20%20%20%20button.type%20%3D%20%22submit%22%3B%0A%20%20%20%20form.append(button)%3B%0A%0A%20%20%20%20document.currentScript.before(form)%3B%0A%20%20%20%20button.click()%3B%0A%20%20"
      

  • CRASH [expected ERROR] /html/browsers/history/the-location-interface/location_replace_session_history.html (#41896)
  • OK [expected TIMEOUT] /html/infrastructure/urls/base-url/document-base-url-window-initiator-is-not-opener.https.window.html (#30970)
  • OK [expected TIMEOUT] /html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html (#29087)
    • PASS [expected TIMEOUT] subtest: &lt;dialog&gt;-contained autofocus element gets focused when the dialog is shown
  • TIMEOUT /html/semantics/embedded-content/media-elements/autoplay-allowed-by-permissions-policy.https.sub.html (#46803)
    • TIMEOUT [expected PASS] subtest: Permissions-Policy header: autoplay * allows same-origin iframes.

      Test timed out
      

  • TIMEOUT /html/semantics/embedded-content/media-elements/preserves-pitch.html (#40352)
    • PASS [expected TIMEOUT] subtest: Speed-ups should not change the pitch when preservesPitch=true
    • PASS [expected NOTRUN] subtest: Slow-downs should not change the pitch when preservesPitch=true
    • TIMEOUT [expected NOTRUN] subtest: Speed-ups should change the pitch when preservesPitch=false

      Test timed out
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/media-elements/src_object_blob.html (#40340)
    • PASS [expected TIMEOUT] subtest: HTMLMediaElement.srcObject blob
  • OK /html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-location-reload.html (#32595)
    • FAIL [expected PASS] subtest: Reloading iframe loading='lazy' before it is loaded: location.reload

      uncaught exception: Error: assert_equals: expected "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src" but got "about:blank"
      

  • TIMEOUT [expected OK] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_other_frame_popup.sub.html (#39702)
    • TIMEOUT [expected FAIL] subtest: Sandboxed iframe can not navigate other frame's popup

      Test timed out
      

  • TIMEOUT [expected OK] /html/syntax/parsing/html5lib_write_single.html?file=processing-instructions (#46206)
    • TIMEOUT [expected FAIL] subtest: &lt;body&gt;&lt;?all-KINDS-of-CaSeS&gt;

      Test timed out
      

    • TIMEOUT [expected FAIL] subtest: &lt;body&gt;&lt;?all-KINDS-of-CaSeS data&gt;

      Test timed out
      

    • TIMEOUT [expected FAIL] subtest: &lt;body&gt;&lt;?user_name&gt;

      Test timed out
      

    • TIMEOUT [expected FAIL] subtest: &lt;body&gt;&lt;?user_name data&gt;

      Test timed out
      

    • TIMEOUT [expected FAIL] subtest: &lt;body&gt;&lt;?S_S-S_S&gt;

      Test timed out
      

    • TIMEOUT [expected FAIL] subtest: &lt;body&gt;&lt;?_x132&gt;

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;script&gt;&lt;?something&gt;&lt;/script&gt;

      Test timed out
      

  • TIMEOUT [expected OK] /html/syntax/parsing/html5lib_write_single.html?file=tests21
    • TIMEOUT [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[foo]]&gt;

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;math&gt;&lt;![CDATA[foo]]&gt;

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;div&gt;&lt;![CDATA[foo]]&gt;

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[foo

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[]]&gt;

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[]] &gt;]]&gt;

      Test timed out
      

    • TIMEOUT [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[]]

      Test timed out
      

    • NOTRUN [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[]
    • NOTRUN [expected PASS] subtest: &lt;svg&gt;&lt;![CDATA[]&gt;a
    • And 13 more unexpected results...
  • OK /infrastructure/testdriver/click_iframe.html
    • FAIL [expected PASS] subtest: TestDriver click on a document in an iframe

      Unhandled rejection: assert_unreached: click failed Reached unreachable code
      

  • OK [expected TIMEOUT] /infrastructure/testdriver/click_nested.html (#43887)
    • FAIL [expected NOTRUN] subtest: TestDriver click method with multiple windows and nested iframe

      can't access property "document", child.frames[2] is undefined
      

  • OK /paint-timing/fcp-only/fcp-out-of-bounds-translate.html
    • PASS [expected FAIL] subtest: First contentful paint fires due to transform-based intersection with document.
  • OK /paint-timing/fcp-only/fcp-svg.html (#45878)
    • PASS [expected FAIL] subtest: First contentful paint fires when SVG becomes contentful.
  • ERROR [expected TIMEOUT] /performance-timeline/not-restored-reasons/abort-block-bfcache.window.html (#42802)
  • TIMEOUT [expected OK] /pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html (#44693)
    • NOTRUN [expected PASS] subtest: touch two-finger pan on 'touch-action: pan-x pan-y'
    • NOTRUN [expected FAIL] subtest: touch two-finger pan on 'touch-action: pinch-zoom'
  • OK /pointerevents/pointerevent_pointercapture_in_frame.html?pen (#45536)
    • FAIL [expected PASS] subtest: Test penpointer capture in same-origin frame: Pointer down at inner frame and set pointer capture.

      assert_true: Timed out waiting for lostpointercapture expected true got false
      

    • FAIL [expected PASS] subtest: Test penpointer capture in same-origin frame: Pointer down at inner frame and set pointer capture to outer frame should not capture.

      assert_array_equals: Received events: innerFrame received pointerdown,innerFrame received pointermove,innerFrame received pointerup,innerFrame received lostpointercapture lengths differ, expected array ["innerFrame received pointerdown", "innerFrame received pointermove", "innerFrame received pointerup"] length 3, got ["innerFrame received pointerdown", "innerFrame received pointermove", "innerFrame received pointerup", "innerFrame received lostpointercapture"] length 4
      

  • OK /preload/prefetch-document.html (#37210)
    • FAIL [expected PASS] subtest: different-site document prefetch with 'as=document' should not be consumed

      assert_equals: expected 2 but got 1
      

  • OK /resource-timing/buffer-full-then-increased.html (#44408)
    • FAIL [expected PASS] subtest: Test that overflowing the buffer and immediately increasing its limit does not trigger the resourcetimingbufferfull event

      assert_equals: Number of entries does not match the expected value. expected 3 but got 1
      

  • OK /resource-timing/test_resource_timing.https.html (#25216)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (script)
  • OK /touch-events/hover-state-caused-by-compatibility-mouse-events.tentative.html (#46277)
    • PASS [expected FAIL] subtest: The compatibility mouse events should set :hover: The compatibility mouse events should be fired
    • PASS [expected FAIL] subtest: The compatibility mouse events should set :hover, but shouldn't be preserved after the target is replaced: The compatibility mouse events should be fired
  • OK /touch-events/single-tap-when-touchend-listener-use-sync-xhr.html (#41175)
    • PASS [expected FAIL] subtest: Click event should be fired when touchend opens synchronous XHR
  • CRASH [expected OK] /trusted-types/require-trusted-types-for.html
  • TIMEOUT /trusted-types/trusted-types-navigation.html?06-10 (#37920)
    • TIMEOUT [expected PASS] subtest: Navigate a frame via anchor with javascript:-urls in report-only mode.

      Test timed out
      

    • NOTRUN [expected TIMEOUT] subtest: Navigate a frame via anchor with javascript:-urls w/ default policy in report-only mode.
  • OK [expected TIMEOUT] /trusted-types/trusted-types-navigation.html?31-35 (#38034)
    • PASS [expected TIMEOUT] subtest: Navigate a frame via form-submission with javascript:-urls in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a frame via form-submission with javascript:-urls w/ default policy in report-only mode.
    • FAIL [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ a default policy throwing an exception in enforcing mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

    • FAIL [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ a default policy throwing an exception in report-only mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

    • FAIL [expected NOTRUN] subtest: Navigate a window via form-submission with javascript:-urls w/ a default policy making the URL invalid in enforcing mode.

      promise_test: Unhandled rejection with value: "Unexpected message received: \"No securitypolicyviolation reported!\""
      

  • TIMEOUT [expected OK] /webstorage/storage_local_setitem_quotaexceedederr.window.html
  • CRASH [expected OK] /webstorage/storage_session_setitem_quotaexceedederr.window.html
Stable unexpected results that are known to be intermittent (13)
  • OK /beacon/beacon-basic.https.window.html (#41723)
    • FAIL [expected PASS] subtest: Payload size restriction should be accumulated: type = string

      assert_false: expected false got true
      

    • PASS [expected FAIL] subtest: Payload size restriction should be accumulated: type = blob
  • TIMEOUT /fetch/metadata/generated/css-images.sub.tentative.html (#29047)
    • TIMEOUT [expected PASS] subtest: background-image sec-fetch-site - Not sent to non-trustworthy same-origin destination

      Test timed out
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.html (#29056)
    • FAIL [expected PASS] subtest: Cross-origin navigation started from unload handler must be ignored

      promise_test: Unhandled rejection with value: object "SecurityError: The operation is insecure."
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/refresh/same-document-refresh.html (#34597)
    • PASS [expected FAIL] subtest: Same-Document Referrer from Refresh
  • OK /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html (#28697)
    • FAIL [expected PASS] subtest: aElement.click() before the load event must NOT replace

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?thereplacement" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/resources/code-injector.html?pipe=sub(none)&amp;code=%0A%20%20%20%20const%20a%20%3D%20document.createElement(%22a%22)%3B%0A%20%20%20%20a.href%20%3D%20%22%2Fcommon%2Fblank.html%3Fthereplacement%22%3B%0A%20%20%20%20document.currentScript.before(a)%3B%0A%20%20%20%20a.click()%3B%0A%20%20"
      

  • TIMEOUT [expected OK] /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-submit.html (#44028)
  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • TIMEOUT [expected FAIL] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: Area element should support autofocus
  • TIMEOUT [expected OK] /html/semantics/embedded-content/media-elements/autoplay-disabled-by-permissions-policy.https.sub.html (#46012, #46804)
    • TIMEOUT [expected PASS] subtest: Permissions-Policy header: autoplay "none" has no effect on the top level document.

      Test timed out
      

    • TIMEOUT [expected FAIL] subtest: Permissions-Policy header: autoplay "none" disallows same-origin iframes.

      Test timed out
      

  • OK [expected TIMEOUT] /html/syntax/parsing/html5lib_write.html?file=processing-instructions (#46205)
  • ERROR [expected OK] /intersection-observer/v2/animated-opacity.html (#40827)
  • OK /resource-timing/buffer-full-add-then-clear.html (#40819)
    • FAIL [expected PASS] subtest: Test that if the buffer is cleared after entries were added to the secondary buffer, those entries make it into the primary one

      assert_equals: Number of entries does not match the expected value. expected 3 but got 0
      

  • OK [expected TIMEOUT] /trusted-types/trusted-types-navigation.html?01-05 (#38975)
    • PASS [expected TIMEOUT] subtest: Navigate a window via anchor with javascript:-urls in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a window via anchor with javascript:-urls w/ default policy in report-only mode.
    • PASS [expected NOTRUN] subtest: Navigate a frame via anchor with javascript:-urls in enforcing mode.
  • TIMEOUT [expected OK] /trusted-types/trusted-types-navigation.html?16-20 (#44835)
    • TIMEOUT [expected PASS] subtest: Navigate a frame via area with javascript:-urls w/ default policy in enforcing mode.

      Test timed out
      

    • NOTRUN [expected FAIL] subtest: Navigate a frame via area with javascript:-urls in report-only mode.
    • NOTRUN [expected PASS] subtest: Navigate a frame via area with javascript:-urls w/ default policy in report-only mode.

@github-actions

Copy link
Copy Markdown

✨ Try run (#30474743087) succeeded.

@mrobinson mrobinson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix!

// the tree can't be compared to anything in the DOM tree.
let control_element = control.to_element();
if control_element.upcast::<Node>().has_parent() {
if control_element.upcast::<Node>().is_in_a_document_tree() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect longer-term these issues will be better fixed by more closely following https://html.spec.whatwg.org/multipage/#create-an-element-for-the-token.

@servo-highfive servo-highfive removed the S-awaiting-review There is new code that needs to be reviewed. label Jul 30, 2026
@mrobinson
mrobinson added this pull request to the merge queue Jul 30, 2026
@servo-highfive servo-highfive added the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Jul 30, 2026
Merged via the queue into servo:main with commit e20c242 Jul 30, 2026
77 checks passed
@servo-highfive servo-highfive removed the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants