Bug 1457711 - Catch errors thrown by console's property previewer; r=nchevobbe
MozReview-Commit-ID: LKsYn5gSn58
This commit is contained in:
@@ -393,6 +393,9 @@ function getMatchedPropsImpl(obj, match, {chainIterator, getProperties}) {
|
|||||||
let iter = chainIterator(obj);
|
let iter = chainIterator(obj);
|
||||||
for (obj of iter) {
|
for (obj of iter) {
|
||||||
let props = getProperties(obj);
|
let props = getProperties(obj);
|
||||||
|
if (!props) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
numProps += props.length;
|
numProps += props.length;
|
||||||
|
|
||||||
// If there are too many properties to event attempt autocompletion,
|
// If there are too many properties to event attempt autocompletion,
|
||||||
@@ -459,12 +462,22 @@ var JSObjectSupport = {
|
|||||||
chainIterator: function* (obj) {
|
chainIterator: function* (obj) {
|
||||||
while (obj) {
|
while (obj) {
|
||||||
yield obj;
|
yield obj;
|
||||||
|
try {
|
||||||
obj = Object.getPrototypeOf(obj);
|
obj = Object.getPrototypeOf(obj);
|
||||||
|
} catch (error) {
|
||||||
|
// The above can throw e.g. for some proxy objects.
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getProperties: function(obj) {
|
getProperties: function(obj) {
|
||||||
|
try {
|
||||||
return Object.getOwnPropertyNames(obj);
|
return Object.getOwnPropertyNames(obj);
|
||||||
|
} catch (error) {
|
||||||
|
// The above can throw e.g. for some proxy objects.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getProperty: function() {
|
getProperty: function() {
|
||||||
@@ -477,12 +490,22 @@ var DebuggerObjectSupport = {
|
|||||||
chainIterator: function* (obj) {
|
chainIterator: function* (obj) {
|
||||||
while (obj) {
|
while (obj) {
|
||||||
yield obj;
|
yield obj;
|
||||||
|
try {
|
||||||
obj = obj.proto;
|
obj = obj.proto;
|
||||||
|
} catch (error) {
|
||||||
|
// The above can throw e.g. for some proxy objects.
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getProperties: function(obj) {
|
getProperties: function(obj) {
|
||||||
|
try {
|
||||||
return obj.getOwnPropertyNames();
|
return obj.getOwnPropertyNames();
|
||||||
|
} catch (error) {
|
||||||
|
// The above can throw e.g. for some proxy objects.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getProperty: function(obj, name, rootObj) {
|
getProperty: function(obj, name, rootObj) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function evaluateJS(input, options = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function autocompletePromise(str, cursor, frameActor) {
|
function autocompletePromise(str, cursor = str.length, frameActor) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
gState.client.autocomplete(str, cursor, resolve, frameActor);
|
gState.client.autocomplete(str, cursor, resolve, frameActor);
|
||||||
});
|
});
|
||||||
@@ -34,13 +34,13 @@ function autocompletePromise(str, cursor, frameActor) {
|
|||||||
let runningInTab = true;
|
let runningInTab = true;
|
||||||
function startTest({worker}) {
|
function startTest({worker}) {
|
||||||
if (worker) {
|
if (worker) {
|
||||||
attachConsoleToWorker(["PageError"], onAttach);
|
attachConsoleToWorker(["PageError"], onAttach.bind(null, true));
|
||||||
} else {
|
} else {
|
||||||
attachConsoleToTab(["PageError"], onAttach);
|
attachConsoleToTab(["PageError"], onAttach.bind(null, false));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let onAttach = async function (aState, response) {
|
let onAttach = async function (isWorker, aState, response) {
|
||||||
gState = aState;
|
gState = aState;
|
||||||
|
|
||||||
let longStrLength = DebuggerServer.LONG_STRING_LENGTH;
|
let longStrLength = DebuggerServer.LONG_STRING_LENGTH;
|
||||||
@@ -71,20 +71,32 @@ let onAttach = async function (aState, response) {
|
|||||||
for (let i = 0; i < ${MAX_AUTOCOMPLETIONS * 2}; i++) {
|
for (let i = 0; i < ${MAX_AUTOCOMPLETIONS * 2}; i++) {
|
||||||
window.largeObject2['a' + i] = i;
|
window.largeObject2['a' + i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.proxy1 = new Proxy({foo: 1}, {
|
||||||
|
getPrototypeOf() { throw new Error() }
|
||||||
|
});
|
||||||
|
window.proxy2 = new Proxy(Object.create(Object.create(null, {foo:{}})), {
|
||||||
|
ownKeys() { throw new Error() }
|
||||||
|
});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
await evaluateJS(script);
|
await evaluateJS(script);
|
||||||
|
|
||||||
let tests = [doAutocomplete1, doAutocomplete2, doAutocomplete3,
|
let tests = [doAutocomplete1, doAutocomplete2, doAutocomplete3,
|
||||||
doAutocomplete4, doAutocompleteLarge1,
|
doAutocomplete4, doAutocompleteLarge1,
|
||||||
doAutocompleteLarge2];
|
doAutocompleteLarge2, doAutocompleteProxyThrowsPrototype,
|
||||||
|
doAutocompleteProxyThrowsOwnKeys];
|
||||||
|
if (!isWorker) {
|
||||||
|
// `Cu` is not defined in workers, then we can't test `Cu.Sandbox`
|
||||||
|
tests.push(doAutocompleteSandbox);
|
||||||
|
}
|
||||||
|
|
||||||
runTests(tests, testEnd);
|
runTests(tests, testEnd);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function doAutocomplete1() {
|
async function doAutocomplete1() {
|
||||||
info("test autocomplete for 'window.foo'");
|
info("test autocomplete for 'window.foo'");
|
||||||
let response = await autocompletePromise("window.foo", 10);
|
let response = await autocompletePromise("window.foo");
|
||||||
let matches = response.matches;
|
let matches = response.matches;
|
||||||
|
|
||||||
is(response.matchProp, "foo", "matchProp");
|
is(response.matchProp, "foo", "matchProp");
|
||||||
@@ -96,7 +108,7 @@ async function doAutocomplete1() {
|
|||||||
|
|
||||||
async function doAutocomplete2() {
|
async function doAutocomplete2() {
|
||||||
info("test autocomplete for 'window.foobarObject.'");
|
info("test autocomplete for 'window.foobarObject.'");
|
||||||
let response = await autocompletePromise("window.foobarObject.", 20);
|
let response = await autocompletePromise("window.foobarObject.");
|
||||||
let matches = response.matches;
|
let matches = response.matches;
|
||||||
|
|
||||||
ok(!response.matchProp, "matchProp");
|
ok(!response.matchProp, "matchProp");
|
||||||
@@ -124,7 +136,7 @@ async function doAutocomplete3() {
|
|||||||
async function doAutocomplete4() {
|
async function doAutocomplete4() {
|
||||||
// Check that completion requests can have no suggestions.
|
// Check that completion requests can have no suggestions.
|
||||||
info("test autocomplete for 'dump(window.foobarObject.)'");
|
info("test autocomplete for 'dump(window.foobarObject.)'");
|
||||||
let response = await autocompletePromise("dump(window.foobarObject.)", 26);
|
let response = await autocompletePromise("dump(window.foobarObject.)");
|
||||||
ok(!response.matchProp, "matchProp");
|
ok(!response.matchProp, "matchProp");
|
||||||
is(response.matches.length, 0, "matches.length");
|
is(response.matches.length, 0, "matches.length");
|
||||||
|
|
||||||
@@ -135,7 +147,7 @@ async function doAutocompleteLarge1() {
|
|||||||
// Check that completion requests with too large objects will
|
// Check that completion requests with too large objects will
|
||||||
// have no suggestions.
|
// have no suggestions.
|
||||||
info("test autocomplete for 'window.largeObject1.'");
|
info("test autocomplete for 'window.largeObject1.'");
|
||||||
let response = await autocompletePromise("window.largeObject1.", 20);
|
let response = await autocompletePromise("window.largeObject1.");
|
||||||
ok(!response.matchProp, "matchProp");
|
ok(!response.matchProp, "matchProp");
|
||||||
info (response.matches.join("|"));
|
info (response.matches.join("|"));
|
||||||
is(response.matches.length, 0, "Bailed out with too many properties");
|
is(response.matches.length, 0, "Bailed out with too many properties");
|
||||||
@@ -147,13 +159,47 @@ async function doAutocompleteLarge2() {
|
|||||||
// Check that completion requests with pretty large objects will
|
// Check that completion requests with pretty large objects will
|
||||||
// have MAX_AUTOCOMPLETIONS suggestions
|
// have MAX_AUTOCOMPLETIONS suggestions
|
||||||
info("test autocomplete for 'window.largeObject2.'");
|
info("test autocomplete for 'window.largeObject2.'");
|
||||||
let response = await autocompletePromise("window.largeObject2.", 20);
|
let response = await autocompletePromise("window.largeObject2.");
|
||||||
ok(!response.matchProp, "matchProp");
|
ok(!response.matchProp, "matchProp");
|
||||||
is(response.matches.length, MAX_AUTOCOMPLETIONS, "matches.length is MAX_AUTOCOMPLETIONS");
|
is(response.matches.length, MAX_AUTOCOMPLETIONS, "matches.length is MAX_AUTOCOMPLETIONS");
|
||||||
|
|
||||||
nextTest();
|
nextTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function doAutocompleteProxyThrowsPrototype() {
|
||||||
|
// Check that completion provides own properties even if [[GetPrototypeOf]] throws.
|
||||||
|
info("test autocomplete for 'window.proxy1.'");
|
||||||
|
let response = await autocompletePromise("window.proxy1.");
|
||||||
|
ok(!response.matchProp, "matchProp");
|
||||||
|
is(response.matches.length, 1, "matches.length");
|
||||||
|
checkObject(response.matches, ["foo"]);
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doAutocompleteProxyThrowsOwnKeys() {
|
||||||
|
// Check that completion provides inherited properties even if [[OwnPropertyKeys]] throws.
|
||||||
|
info("test autocomplete for 'window.proxy2.'");
|
||||||
|
let response = await autocompletePromise("window.proxy2.");
|
||||||
|
ok(!response.matchProp, "matchProp");
|
||||||
|
is(response.matches.length, 1, "matches.length");
|
||||||
|
checkObject(response.matches, ["foo"]);
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doAutocompleteSandbox() {
|
||||||
|
// Check that completion provides inherited properties even if [[OwnPropertyKeys]] throws.
|
||||||
|
info("test autocomplete for 'Cu.Sandbox.'");
|
||||||
|
let response = await autocompletePromise("Cu.Sandbox.");
|
||||||
|
ok(!response.matchProp, "matchProp");
|
||||||
|
let keys = Object.getOwnPropertyNames(Object.prototype).sort();
|
||||||
|
is(response.matches.length, keys.length, "matches.length");
|
||||||
|
checkObject(response.matches, keys);
|
||||||
|
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
|
||||||
function testEnd()
|
function testEnd()
|
||||||
{
|
{
|
||||||
// If this is the first run, reload the page and do it again
|
// If this is the first run, reload the page and do it again
|
||||||
|
|||||||
Reference in New Issue
Block a user