browser_exception_leak.js (2626B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 */ 5 6 // For bug 1471989, test that an exception saved by chrome code can't leak the page. 7 8 add_task(async function test() { 9 const url = 10 "http://mochi.test:8888/browser/js/xpconnect/tests/browser/browser_consoleStack.html"; 11 let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); 12 let browser = gBrowser.selectedBrowser; 13 let innerWindowId = browser.innerWindowID; 14 15 let stackTraceEmpty = await ContentTask.spawn( 16 browser, 17 { innerWindowId }, 18 async function (args) { 19 let { TestUtils } = ChromeUtils.importESModule( 20 "resource://testing-common/TestUtils.sys.mjs" 21 ); 22 let { Assert } = ChromeUtils.importESModule( 23 "resource://testing-common/Assert.sys.mjs" 24 ); 25 26 const ConsoleAPIStorage = Cc[ 27 "@mozilla.org/consoleAPI-storage;1" 28 ].getService(Ci.nsIConsoleAPIStorage); 29 let consoleEvents = ConsoleAPIStorage.getEvents(args.innerWindowId); 30 Assert.equal( 31 consoleEvents.length, 32 1, 33 "Should only be one console event for the window" 34 ); 35 36 // Intentionally hold a reference to the console event. 37 let leakedConsoleEvent = consoleEvents[0]; 38 39 // XXX I think this is intentionally leaking |doc|. 40 // eslint-disable-next-line no-unused-vars 41 let doc = content.document; 42 43 let promise = TestUtils.topicObserved("inner-window-nuked", subject => { 44 let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data; 45 return id == args.innerWindowId; 46 }); 47 content.location = "http://mochi.test:8888/"; 48 await promise; 49 50 // This string should be empty. For that to happen, two things 51 // need to be true: 52 // 53 // a) ConsoleCallData::mStack is not null. This means that the 54 // stack trace was not reified before the page was nuked. If it 55 // was, then the correct |filename| value would be stored on the 56 // object. (This is not a problem, except that it stops us from 57 // testing the next condition.) 58 // 59 // b) ConsoleData::mStack.mStack is null. This means that the 60 // JSStackFrame is keeping alive the JS object in the page after 61 // the page was nuked, which leaks the page. 62 return leakedConsoleEvent.stacktrace[0].filename; 63 } 64 ); 65 66 is( 67 stackTraceEmpty, 68 "", 69 "JSStackFrame shouldn't leak mStack after window nuking" 70 ); 71 72 BrowserTestUtils.removeTab(newTab); 73 });