Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1212 +/- ##
==========================================
- Coverage 62.31% 61.26% -1.06%
==========================================
Files 40 42 +2
Lines 3930 4009 +79
==========================================
+ Hits 2449 2456 +7
- Misses 1481 1553 +72 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
vringar
force-pushed
the
investigate/legacy-error-stack-trace
branch
from
July 20, 2026 22:54
37ddc30 to
6c5ad4d
Compare
vringar
force-pushed
the
investigate/legacy-error-stack-trace
branch
from
August 25, 2026 09:18
6c5ad4d to
70d3d73
Compare
vringar
force-pushed
the
investigate/legacy-error-stack-trace
branch
from
September 6, 2026 14:55
70d3d73 to
cd44a22
Compare
…ll (investigation, do-not-merge)
…gacy instrument wrapper (investigation, do-not-merge) Empirical companion to the error.stack surfacing test. A self-contained page models the page-world instrument wrapper frame, installs an Error.prototype.stack getter patch in two variants (crude = drop top frame; targeted = drop only instrument frames), and measures the cost. Findings (Firefox 152): the wrapper-throwing web-API cases (atob/getImageData) raise DOMExceptions whose stack comes from a SEPARATE accessor, so the patch is inert for them; where it applies (real Errors) crude over-pops legitimate page frames, both variants leave a page-detectable non-native stack getter, and both are defeated cross-realm by a pristine iframe-realm getter. Popping the top frame is a page-world cross-realm ceiling, not a viable fix.
vringar
force-pushed
the
investigate/legacy-error-stack-trace
branch
from
September 6, 2026 20:24
cd44a22 to
eba7f78
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Investigation / do-not-merge
This PR is stacked on #1211 (
test/assert-rewrite-helpers). It now carriestwo investigation commits (both end in
pytest.failto print their evidencein the CI log; both EXPECTED TO FAIL by design — do not merge):
surface ... error.stack— reproduces fix(extension): strip moz-extension frames from legacy instrument error stacks #1207's flow and dumps the literalpage-observable
error.stackof a thrown instrumented call.demonstrate that popping the top stack frame cannot hide the wrapper—answers the follow-up question below.
Commit 1 — what the leak actually is
Faithfully reproduces #1207's (
harden/legacy-error-stacks) flow: instrumentswindow.atob, page code callsatob("not valid base64 !@#$%")so it throws anInvalidCharacterError, the page catches it and stashese.stackintodocument.title; aCaptureStackCommandreads the title back across the processboundary.
#1207 asserts
"moz-extension://" not in stack— a no-op: the legacyinstrument runs in the page world, so there is never a
moz-extension://frame to leak (the assertion passes vacuously). This commit instead surfaces
the captured stack via
pytest.fail. The real, page-observable leak #1207'sassertion misses is a page-attributed wrapper frame
(
getInstrumentJS/instrumentFunction/<) sitting as the top frame:Commit 2 — can the instrument "pop the top frame" to hide that wrapper?
The follow-up hypothesis: have the page-world instrument patch
error.stacktodrop the top frame, hiding the wrapper. Verdict (empirically): no — this is
another page-world cross-realm ceiling (the #56/#57 family), not a cheap win.
Do not ship an instrument patch. Measured on Firefox 152 (also reproduced
direct-selenium with the REAL inlined
getInstrumentJS):How Firefox exposes
error.stack(dictates the patch).Error.prototype.stackis a native accessor (
get stack,[native code]); instances have no ownstackdata property. So a patch must redefine that accessor. ButDOMException.prototype.stackis a SEPARATE native accessor — and the#1207/#1212 throw cases (
atob,getImageData) raise aDOMException(
InvalidCharacterError/IndexSizeError), whose stack does not come fromError.prototype. So anError.prototype.stackpatch is inert for exactlythe cases #1207 cared about (
dom_hidesWrapper: false, both variants); you wouldhave to also patch every
DOMException/Errorsubtype'sstackaccessor.Two patch variants, where the patch does apply (a real
Error,JSON.parse("{bad")→SyntaxError, routed through the wrapper):get, notget stack; JS-bodytoString)Over-pop (crude), verbatim. A legit page Error with no wrapper on its
stack — crude silently strips its real top frame
legitPlainErrorTop:Crude corrupts the top frame of every page Error — a correctness disaster and
itself a trivial detector (
function f(){return new Error().stack} f()no longershows
f). Targeted avoids over-pop but is still non-native-detectable.Cross-realm bypass (both variants), verbatim. The same
Error, read main-realm(patched, wrapper hidden) vs. through a pristine, never-patched
Error.prototypestack getter pulled from a same-origin
<iframe>realm:The iframe realm's getter stays native and untouched by the main-realm patch and
re-derives the unfiltered stack, wrapper and all — the same architectural wall as
the #57
toStringbypass. A main-realm-only patch cannot close it.Why net-negative: inert for the actual DOMException throws unless you also
patch every error subtype's
stack; detectable (non-native accessor — the sametoString-wall tell as #57); crude over-pops legitimate page frames; targeted still
non-native-detectable and still cross-realm-bypassed. The wrapper-frame leak is a
property of running in the page world; a page-world stack-getter patch is defeated
by the same cross-realm ceiling as the toString leak.
The second commit's test asserts this ceiling, then
pytest.fail-dumps the fullmeasured JSON so the literal stacks appear in the CI log.
Purpose
Let reviewers read the literal page-observable
error.stack(commit 1) and theempirical evidence that "pop the top frame" is a ceiling, not a fix (commit 2),
against ground truth — before deciding whether any error-stack hardening is worth
shipping for the legacy instrument.