Source code
Revision control
Copy as Markdown
Other Tools
// |jit-test| error:finished
var g = newGlobal({newCompartment: true});
g.evaluate(`
// Override Error.prototype.name with a getter that nukes CCWs
Object.defineProperty(Error.prototype, 'name', {
get: function() {
// Nuke all cross-compartment wrappers pointing into this realm.
// This makes the CCW in the main compartment (that roots our ErrorObject)
// become a dead proxy, removing the only reference to our ErrorObject.
nukeAllCCWs();
// Force a full GC to tenure the ErrorObject and compact heap.
// ErrorObject survives this GC because it's 'this' (on the C++ stack).
gc();
// Set maxBytes to current gcBytes so the NEXT allocation triggers GC.
// The next GC will collect the ErrorObject, freeing its JSErrorReport.
gcparam('maxBytes', gcparam('gcBytes'));
// Return undefined (not a string) to force fallback to reportp->exnType
// and then reportp->newMessageString (both UAF after GC collects ErrorObject)
return undefined;
}
});
// Create the Error object in this compartment
this.err = new Error("finished");
`);
// Get a CCW (cross-compartment wrapper) to the ErrorObject.
// Then clear the reference in compartment A so the only reference is through our CCW.
// Then throw the foreign error at top level.
var foreignError = g.err;
g.err = null;
throw foreignError;