Skip to content

fix(window): replace cross-origin surface caches with native bindings - #1594

Merged
ldm0 merged 5 commits into
mainfrom
panic-fix39192
Oct 16, 2026
Merged

ldm0 merged 5 commits into
mainfrom
panic-fix39192

Conversation

@ldm0

@ldm0 ldm0 commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Cross-origin Window access builds JavaScript surfaces and calls captured WeakMap intrinsics. Watchdog termination can fail those calls and panic. On personalshop.ch, Adform's ancestor search also loops because top is a caller-local projection while following parent reaches the actual top WindowProxy.

This change fixes the ancestor identity bug and dispatches cross-origin access-check handlers through generated native member tables. It replaces the earlier WeakMap termination fix by removing that cache entirely.

The first three commits separate the behavior fix, reusable binding infrastructure, and Window/Location migration:

  1. Preserve the actual top WindowProxy throughout the ancestor chain. A three-origin nested-frame search that exceeded a 10-step bound before now reaches top after 2 steps, matching Chromium.
  2. Add WebApiCrossOrigin declarations. Cache stateless FunctionTemplates per isolate and let V8 provide each accessing Context's function instances. Callbacks resolve their actual receiver without capturing a target or observer.
  3. Dispatch Window and Location through native member tables, removing the WeakMap cache and per-child intermediate access surfaces. Keep per-Window Location wrapper identity and resolve indexed/named children from the current frame tree.

Two follow-up commits address review findings:

  1. d919e889a6: Propagate Location key installation, Proxy wrapping, and private-slot failures through shared, live, detached, and popup construction. Cache the Window facade only after initialization succeeds. Regression tests reject property initialization and interrupt V8 during partial initialization, then verify recovery without a partial Location identity.
  2. 9f13d2cab9: Restrict named child Window properties to the first matching child in current document-tree order whose committed Document origin matches the target parent's origin. Compare origin tuples and opaque identities without document.domain relaxation. Preserve numeric access and same-origin DOM id/name handling. Cover three origins, nested parents, duplicate ordering, removal, navigation, descriptors, queries, and fallback collisions; avoid constructing a discarded children list during named lookup.

The migration also applies cross-origin descriptor/fallback rules: configurable, non-enumerable descriptors; undefined symbol fallbacks; SecurityError for unsupported descriptors; named child windows precede fallbacks and may shadow names such as document. Tests cover removal, navigation, borrowed receivers, function realms/identity, termination, and garbage collection.

The design follows Blink's native cross-origin member support and the HTML WindowProxy rules. The controlled Chromium comparison also checked receiver errors, mutation restrictions, Location identity, and named collisions. The new named-child origin restriction follows the current HTML rule; local Chromium 145.0.7632.116 still exposes explicitly named cross-origin children in the three-origin fixture, so this restriction is a deliberate conformance difference.

Validation (24 Cargo build jobs, each commit checked separately):

  • cargo fmt --all

  • cargo clippy --workspace --all-targets --all-features -- -D warnings

  • cargo nextest run --no-fail-fast: 20,223 passed, 18 skipped at the Location follow-up; 20,225 passed, 18 skipped at the named-child follow-up.

  • cargo build -p moli and the three-origin differential fixture.

  • At native bindings commit 817e17d, three independent 40-second personalshop.ch runs loaded trackpoint-async.js and recorded no panic or watchdog termination. The previous profile spent approximately 8 seconds in Adform's ancestor loop before termination. The page still remained interactive at the end of these observations; this does not claim complete third-party resource loading.

  • At follow-up HEAD 9f13d2cab9, the three-origin fixture returns SecurityError for foreign named getters/descriptors and the first duplicate, while valid named access and cross-origin numeric indexing remain available.

  • A new 40-second personalshop.ch observation at the follow-up HEAD loaded Adform trackpoint-async.js, recorded no panic or watchdog termination, and reached document.readyState=complete.

  • CLI moli fetch https://personalshop.ch --timeout 60000: exit 0, 211,338 bytes of rendered HTML, empty stderr. The timeout value is in milliseconds.

Supersedes #1586, whose WeakMap cache failure path is removed by the native bindings.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Spider Bench A/B

✅ All benchmark browser service runs completed; results are informational.

Public HEAD: 184 / 240 rows; 38 / 48 sites produced rows; 10 unexpected empty sites.

✅ Deterministic fixture contract is clean.

Common ancestor 07368cea9a72 → HEAD 9f13d2cab92d; benchmark order: head-first; workflow: success.

Public 48-site run · informational

Metric Base HEAD Δ
Run status success success —
Extracted rows / contract 184 / 240 184 / 240 0 (0.00%)
Contract fill 76.67% 76.67% 0.00 pp (0.00%)
Sites with rows 38 / 48 38 / 48 0 (0.00%)
Sites meeting row contract 36 / 48 36 / 48 0 (0.00%)
Unexpected empty sites 10 10 0 (0.00%)
Partial-row sites 2 2 0 (0.00%)
Site outcomes extracted: 37; HTTP error + rows: 1; empty: 7; HTTP error + empty: 1; snapshot error + empty: 2 extracted: 36; HTTP error + rows: 2; empty: 7; HTTP error + empty: 1; snapshot error + empty: 2 —
Observed duration 52.56 s 60.49 s +7.92 s (+15.08%)
Estimated CPU 51.15 s 50.01 s -1.14 s (-2.23%)
Peak PSS 276.62 MiB 285.04 MiB +8.41 MiB (+3.04%)
Peak RSS 279.63 MiB 287.63 MiB +8.00 MiB (+2.86%)
Peak threads 26 27 +1 (+3.85%)
Mismatched sites 0 0 0
Timeout with items 0 0 0
Category rows Base HEAD Δ
news 35 / 40 35 / 40 0
stocks 20 / 40 20 / 40 0
tech 35 / 40 35 / 40 0
sports 27 / 40 27 / 40 0
games 37 / 40 37 / 40 0
life 30 / 40 30 / 40 0

Public-site content, timing, and memory are noisy. This single A/B run reports evidence only; site outcome counts explain missing rows without treating them as a deterministic regression.

CPU and memory timelines

These are bounded 40-point views of the same complete process-tree samples used by the HTML report. CPU uses 100% per occupied logical core; memory lines are RSS first and PSS second when complete PSS samples are available.

Base

xychart-beta
    title "Base CPU"
    x-axis "Elapsed seconds" [1.537, 2.538, 3.039, 4.04, 4.542, 6.044, 7.546, 9.047, 10.048, 11.55, 13.051, 14.554, 16.056, 17.557, 19.059, 20.562, 22.064, 23.566, 25.068, 26.571, 27.571, 29.072, 30.574, 32.077, 33.579, 35.081, 36.582, 38.084, 39.586, 41.088, 42.59, 44.092, 45.092, 46.594, 48.095, 49.597, 51.099, 52.099]
    y-axis "CPU percent" 0 --> 500
    line [69.84, 117.94, 129.74, 145.73, 129.68, 139.98, 165.59, 157.94, 155.85, 143.96, 119.89, 119.78, 33.98, 29.97, 2, 11.97, 0, 87.92, 95.89, 2, 39.98, 79.99, 111.93, 99.85, 131.71, 125.91, 83.95, 137.82, 157.81, 99.88, 11.98, 139.87, 89.97, 17.98, 115.9, 125.83, 125.89, 200.05]
Loading
xychart-beta
    title "Base memory: RSS then PSS"
    x-axis "Elapsed seconds" [0.034, 1.537, 2.538, 3.039, 4.04, 4.542, 6.044, 7.546, 9.047, 10.048, 11.55, 13.051, 14.554, 16.056, 17.557, 19.059, 20.562, 22.064, 23.566, 25.068, 26.571, 27.571, 29.072, 30.574, 32.077, 33.579, 35.081, 36.582, 38.084, 39.586, 41.088, 42.59, 44.092, 45.092, 46.594, 48.095, 49.597, 51.099, 52.099, 52.562]
    y-axis "Memory MiB" 0 --> 500
    line [12.35, 92.7, 126.96, 141.38, 154.4, 144.25, 170.68, 163.87, 193.9, 194.06, 188.09, 198.88, 166.02, 169.74, 176.26, 176.59, 150.18, 149.23, 184.16, 168.45, 161.54, 162.39, 150.93, 169.16, 279.63, 214.73, 242.55, 162.1, 197.88, 167.14, 169.39, 152.93, 206.49, 195.93, 163.7, 187.52, 187.45, 176.02, 204.78, 0]
    line [9.16, 89.18, 123.57, 137.85, 150.91, 140.75, 167.17, 160.32, 190.36, 190.26, 184.87, 195.33, 162.46, 166.21, 172.68, 173.01, 146.6, 145.66, 180.58, 164.87, 157.96, 158.76, 147.35, 165.25, 276.62, 211.16, 237.93, 158.54, 194.34, 163.76, 165.08, 149.35, 202.78, 192.37, 160.12, 183.94, 184.25, 172.47, 201.21, 0]
Loading

HEAD

xychart-beta
    title "HEAD CPU"
    x-axis "Elapsed seconds" [1.541, 3.043, 3.543, 4.545, 5.045, 6.548, 8.55, 10.051, 12.055, 13.557, 15.058, 17.062, 18.562, 20.065, 22.069, 23.569, 25.07, 27.07, 28.571, 30.575, 32.077, 33.58, 35.583, 37.085, 38.588, 40.589, 42.091, 43.592, 45.594, 47.097, 48.599, 50.601, 52.102, 54.105, 55.607, 57.107, 59.111, 60.112]
    y-axis "CPU percent" 0 --> 500
    line [115.96, 123.79, 129.96, 105.93, 137.79, 139.67, 95.87, 192.09, 141.64, 115.84, 0, 2, 2, 0, 93.98, 117.97, 65.99, 0, 41.96, 81.95, 1.99, 2, 129.86, 103.85, 135.69, 147.91, 123.64, 105.85, 36, 79.76, 53.94, 119.87, 79.88, 2, 125.81, 202, 125.75, 209.65]
Loading
xychart-beta
    title "HEAD memory: RSS then PSS"
    x-axis "Elapsed seconds" [0.04, 1.541, 3.043, 3.543, 4.545, 5.045, 6.548, 8.55, 10.051, 12.055, 13.557, 15.058, 17.062, 18.562, 20.065, 22.069, 23.569, 25.07, 27.07, 28.571, 30.575, 32.077, 33.58, 35.583, 37.085, 38.588, 40.589, 42.091, 43.592, 45.594, 47.097, 48.599, 50.601, 52.102, 54.105, 55.607, 57.107, 59.111, 60.112, 60.487]
    y-axis "Memory MiB" 0 --> 500
    line [12.11, 110.45, 137.81, 138.45, 124.52, 164.04, 182.69, 153.64, 184.91, 191.89, 171.8, 165.39, 150.07, 150.07, 150, 162.54, 188.98, 155.09, 150.54, 150.17, 147.12, 148.43, 146.6, 163.66, 287.63, 212, 239.24, 168.82, 166.39, 155.66, 167.06, 143.9, 200.49, 174.73, 161.25, 175.41, 170.86, 171.49, 198.75, 0]
    line [9.22, 107.02, 134.36, 134.99, 121.14, 160.68, 179.2, 150.11, 181.51, 188.26, 168.34, 161.88, 146.56, 146.56, 146.48, 159.3, 184.97, 151.56, 147.01, 146.64, 143.6, 144.91, 143.07, 160.05, 285.04, 208.55, 235.84, 165.22, 162.79, 152.13, 163.41, 140.37, 197.32, 171.2, 157.73, 171.89, 167.33, 168, 195.23, 0]
Loading

Deterministic fixture · required contract

The fixture exercises 15 routes: 8 are expected to emit rows and 7 intentionally exercise empty, loading, or timeout behavior.

Metric Base HEAD Δ
Run status success success —
Extracted rows / contract 40 / 40 40 / 40 0 (0.00%)
Contract fill 100.00% 100.00% 0.00 pp (0.00%)
Sites with rows 8 / 15 8 / 15 0 (0.00%)
Sites meeting row contract 15 / 15 15 / 15 0 (0.00%)
Unexpected empty sites 0 0 0
Partial-row sites 0 0 0
Site outcomes extracted: 7; HTTP error + rows: 1; empty: 3; timeout + empty: 4 extracted: 7; HTTP error + rows: 1; empty: 3; timeout + empty: 4 —
Observed duration 19.86 s 19.87 s +0.01 s (+0.06%)
Estimated CPU 0.40 s 0.41 s +0.01 s (+2.74%)
Peak PSS 67.55 MiB 67.36 MiB -0.18 MiB (-0.27%)
Peak RSS 70.49 MiB 70.24 MiB -0.25 MiB (-0.35%)
Peak threads 18 18 0 (0.00%)
Mismatched sites 0 0 0
Timeout with items 0 0 0

Full HTML, JSON, CSV, logs, and page snapshots: workflow run and full spider-bench-results artifact.

The public-web A/B is informational. The exact HEAD fixture contract runs as a separate required CI check; timing and public-site content deltas remain non-blocking.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

CI Regression Report

Source CI run · source state at render: in_progress · artifacts: 6/6

Check Status Signal
Release regression ✅ HEAD/base failures 0/0; raw binary +0.007222%
Frontend differential ✅ 1,020/1,020 cases matched; 0 issues
Agent episodes ✅ 8/8 Moli episodes passed; 0 failures
Runtime/CDP contracts ✅ 26 contract cases; 0 failures
CDP smoke ✅ 52/52 groups passed; 621 scenarios
WebMainBench ✅ 545/545 completed; 0 unexpected failures
Release regression — ✅ HEAD/base failures 0/0; raw binary +0.007222%

Package and image size

Metric Base HEAD Delta Delta %
Raw binary 153.07 MiB 153.08 MiB +11.32 KiB +0.007222%
Stripped binary 106.38 MiB 106.39 MiB +4.00 KiB +0.003672%
gzip binary 52.71 MiB 52.71 MiB +1.59 KiB +0.002951%
Rootfs 159.97 MiB 159.98 MiB +10.00 KiB +0.006105%
gzip rootfs 61.75 MiB 61.75 MiB +3.78 KiB +0.005982%

Startup latency and PSS

Case Base p50 HEAD p50 Delta Base PSS HEAD PSS Delta
Serve ready 27.25 ms 27.18 ms −0.07 ms 4.14 MiB 4.78 MiB +656.00 KiB
CDP first page 49.74 ms 49.14 ms −0.60 ms 4.24 MiB 4.48 MiB +249.00 KiB
CDP warm page 12.62 ms 12.08 ms −0.54 ms 50.54 MiB 50.99 MiB +464.50 KiB
CLI about:blank 15.25 ms 14.37 ms −0.89 ms 4.82 MiB 4.42 MiB −407.00 KiB
CLI local JS 18.22 ms 18.97 ms +0.76 ms 2.93 MiB 2.89 MiB −44.00 KiB

Concurrency matrix

Concurrency Base p50 HEAD p50 Delta Base PSS HEAD PSS Delta HEAD failures Unstable B/H
1 18.00 ms 17.07 ms −0.93 ms 798.00 KiB 795.00 KiB −3.00 KiB 0 0/0
5 20.87 ms 19.97 ms −0.90 ms 13.79 MiB 12.91 MiB −902.00 KiB 0 0/0
10 19.53 ms 19.04 ms −0.48 ms 15.73 MiB 19.05 MiB +3.32 MiB 0 0/0
25 20.39 ms 19.47 ms −0.92 ms 41.24 MiB 15.65 MiB −25.59 MiB 0 0/0
100 19.68 ms 20.22 ms +0.54 ms 13.58 MiB 18.88 MiB +5.29 MiB 0 0/0
Frontend differential — ✅ 1,020/1,020 cases matched; 0 issues
Match DOM mismatch Diagnostic mismatch Moli error Reference error Infrastructure error Mismatched frames Duration
1,020 0 0 0 0 0 0 6m 30.31s
Agent episodes · Moli vs Chromium — ✅ 8/8 Moli episodes passed; 0 failures
Fast contract Episodes Passed Assertions Ready p50 Episode p50
Moli 8 8 47/47 4.27 ms 25.30 ms
Chromium 8 8 47/47 253.51 ms 83.20 ms
Operation p50 Chromium Moli Delta Delta %
navigate 42.06 ms 6.49 ms −35.57 ms −84.57%
observe 0.88 ms 0.89 ms +0.02 ms +1.87%
fill 3.68 ms 3.37 ms −0.31 ms −8.34%
click 4.22 ms 4.02 ms −0.19 ms −4.57%
Idle-resource episode Peak RSS Peak PSS Average CPU Peak CPU Peak processes Sampler
Moli 66.42 MiB 63.70 MiB 0.70% 10.01% 1 ✅
Chromium 1306.74 MiB 336.58 MiB 1.88% 95.11% 13 ⚠️ PSS partial
Runtime and CDP session contracts — ✅ 26 contract cases; 0 failures
Suite Cases Failures Median case p50 Median case p95 Median peak PSS p50
Synthetic fetch 13 0 18.24 ms 19.18 ms 887.00 KiB
Long-lived CDP session 13 0 18.09 ms 19.04 ms —
CDP smoke — ✅ 52/52 groups passed; 621 scenarios

Workers: 4 · cumulative group time: 138.26 s · failed groups: 0

Slowest group Scenarios Duration Status
scrollbar-visibility 22 13.87 s ✅
target-lifecycle 24 11.28 s ✅
chromium-cdp 56 9.11 s ✅
dom-input 27 9.09 s ✅
multi-page 45 8.12 s ✅
WebMainBench · 545 pages — ✅ 545/545 completed; 0 unexpected failures
Completed Successful Expected DNS failure Unexpected failures Panics Crashes Timeouts Empty output
545/545 544 1 0 0 0 0 0

Frozen HTML · Linux · --wait done · 45 seconds per page · no retries. Content quality is evaluated separately.

Diagnostics: webmainbench-results — every page's Markdown, stderr, and exit status. Source run and artifacts

All artifact fields are parsed by the trusted default-branch renderer; missing or invalid inputs remain visible as unavailable.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Sequential Navigation Soak A/B

⚠️ HEAD did not produce a complete resilience/memory observation: HEAD network_order_violations is not 0.

One browser process, one target, and one CDP session navigate CSDN → SegmentFault → Huaban → example.com repeatedly. This run issued 200 Page.navigate commands per binary.

Common ancestor 07368cea9a → HEAD 9f13d2cab9; benchmark order: head-first; workflow: failure.

Session resilience

Metric Base HEAD
Attempted / planned 200 / 200 200 / 200
Direct observable pass 186 / 200 195 / 200
Failures / recovered 14 / 14 5 / 5
Recovery failures 0 0
Lifecycle order violations 0 0
Network order violations 0 2
Wall time 846.7 s 686.4 s

A public-page failure is reported separately from an unrecoverable session. The soak requires all navigation attempts, zero failed recovery, zero lifecycle/network ordering violations, and complete resource evidence.

Process-tree memory

Metric Base HEAD Δ
Boundary samples 200 200 0
Boundary RSS samples 200 200 0
Boundary PSS samples 200 200 0
Periodic peak RSS 240.7 MiB 247.7 MiB +7.0 MiB
Periodic peak PSS 239.1 MiB 243.9 MiB +4.8 MiB
RSS · first 10 avg 167.5 MiB 156.2 MiB -11.4 MiB
RSS · last 10 avg 180.3 MiB 177.8 MiB -2.5 MiB
RSS · last − first window +12.7 MiB +21.6 MiB +8.9 MiB
RSS · warm slope / 100 nav +4.2 MiB +1.6 MiB -2.6 MiB
PSS · first 10 avg 164.9 MiB 152.6 MiB -12.3 MiB
PSS · last 10 avg 178.6 MiB 174.9 MiB -3.6 MiB
PSS · last − first window +13.7 MiB +22.3 MiB +8.6 MiB
PSS · warm slope / 100 nav +4.2 MiB +1.8 MiB -2.4 MiB
Peak file descriptors 67 62 -5
Peak threads 31 31 0

HEAD memory by 50-navigation quarter

HEAD range Avg RSS Final RSS Peak RSS Avg PSS Final PSS Peak FD
1–50 174.0 MiB 168.4 MiB 220.4 MiB 170.6 MiB 165.2 MiB 54
51–100 179.2 MiB 168.8 MiB 221.9 MiB 176.2 MiB 166.8 MiB 54
101–150 180.5 MiB 165.0 MiB 225.5 MiB 177.8 MiB 162.1 MiB 54
151–200 178.9 MiB 174.9 MiB 208.5 MiB 176.0 MiB 171.9 MiB 53

Raw reports and per-navigation boundary samples: workflow run and full sequential-navigation-soak-results artifact.

Public-site timing and memory are observational. Use the A/B deltas and trend shape as evidence, not as a deterministic performance threshold.

@ldm0
ldm0 force-pushed the panic-fix39192 branch 2 times, most recently from dcdd687 to 107156b Compare October 16, 2026 11:23
ldm0 added 3 commits October 16, 2026 22:56
Cross-origin child realms used caller-local top projections while following
parent reached the actual top WindowProxy. Ancestor searches could then loop
on the real top's self-parent until the watchdog terminated execution.

Use the stable top WindowProxy throughout the ancestor chain and message
endpoint resolution. Add a bounded nested-frame regression for the Adform
ancestor search observed on personalshop.ch.
Generate stateless method and accessor tables with receiver checks and native
value callbacks. Cache FunctionTemplates per isolate and use V8's per-context
function instances, without retaining target Windows or observer realms.

Cover function identity, realm prototypes, descriptors, receiver validation,
exception and termination propagation, and context collection.
Replace WeakMap-backed Window surfaces with native access-check dispatch.
Keep per-Window Location identity and resolve dynamic children from the
current frame tree. Reuse the ordinary Window accessor value helpers.

Apply cross-origin descriptor and fallback rules, preserve borrowed receiver
behavior, and cover navigation, named collisions, removal, and realm teardown.
@ldm0 ldm0 changed the title fix(window): do not abort when script termination hits the cross-origin surface cache fix(window): replace cross-origin surface caches with native bindings Oct 16, 2026
ldm0 added 2 commits October 17, 2026 02:32
Share fallible Location initialization across live, detached, and shared wrappers. Propagate key, Proxy, and private-slot failures through Window construction and publish cached facades only after initialization succeeds.

Cover rejected property initialization and V8 termination after a partial installation, including recovery without publishing an incomplete Location identity.
Select the first named child in current document-tree order, then compare its committed Document origin with the target parent. Keep opaque origin identity and tuple-origin comparisons separate from document.domain access relaxation.

Apply the property-set rule to native bindings and facade names while preserving numeric access and same-origin Document id/name fallbacks. Cover three origins, nested parents, duplicate reordering, removal, navigation, descriptors, queries, and fallback collisions through the real task executor.
@ldm0
ldm0 merged commit 468533c into main Oct 16, 2026
38 of 40 checks passed
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.

1 participant