Commit 43c775f2 authored by Aleksei Koziatinskii's avatar Aleksei Koziatinskii Committed by Commit Bot

inspector: debug-evaluate: allow setters on temporary Date object

Eager evaluation in DevTools console relies on the builtins side
effect attribution.

Setters on Date object should be marked as no side effects if called
on the temporary object.

This bug was uncovered after considering screenshot from a tweet [1].

[1] https://twitter.com/shuding_/status/1362132984376160256

Change-Id: Iedc0e29e2bdab719304e2f0a0435845f24eaaadc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2703459Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72835}
parent 76a2ab06
......@@ -834,6 +834,23 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtins::Name id) {
case Builtins::kMapPrototypeClear:
case Builtins::kMapPrototypeDelete:
case Builtins::kMapPrototypeSet:
// Date builtins.
case Builtins::kDatePrototypeSetDate:
case Builtins::kDatePrototypeSetFullYear:
case Builtins::kDatePrototypeSetHours:
case Builtins::kDatePrototypeSetMilliseconds:
case Builtins::kDatePrototypeSetMinutes:
case Builtins::kDatePrototypeSetMonth:
case Builtins::kDatePrototypeSetSeconds:
case Builtins::kDatePrototypeSetTime:
case Builtins::kDatePrototypeSetUTCDate:
case Builtins::kDatePrototypeSetUTCFullYear:
case Builtins::kDatePrototypeSetUTCHours:
case Builtins::kDatePrototypeSetUTCMilliseconds:
case Builtins::kDatePrototypeSetUTCMinutes:
case Builtins::kDatePrototypeSetUTCMonth:
case Builtins::kDatePrototypeSetUTCSeconds:
case Builtins::kDatePrototypeSetYear:
// RegExp builtins.
case Builtins::kRegExpPrototypeTest:
case Builtins::kRegExpPrototypeExec:
......
Tests side-effect-free evaluation
Paused on 'debugger;'
Running test: basicTest
Paused on "debugger;"
f() returns 1
g() returns 2
f() returns 1
g() throws EvalError
Running test: testDate
someGlobalDate.setDate(10) : throws
new Date().setDate(10) : ok
someGlobalDate.setFullYear(1991) : throws
new Date().setFullYear(1991) : ok
someGlobalDate.setHours(0) : throws
new Date().setHours(0) : ok
someGlobalDate.getDate() : ok
new Date().getDate() : ok
someGlobalDate.getFullYear() : ok
new Date().getFullYear() : ok
someGlobalDate.getHours() : ok
new Date().getHours() : ok
......@@ -5,6 +5,7 @@
let {session, contextGroup, Protocol} = InspectorTest.start('Tests side-effect-free evaluation');
contextGroup.addScript(`
var someGlobalDate = new Date();
function testFunction()
{
var o = 0;
......@@ -15,43 +16,40 @@ function testFunction()
}
//# sourceURL=foo.js`);
Protocol.Debugger.enable();
Protocol.Debugger.oncePaused().then(debuggerPaused);
Protocol.Runtime.evaluate({ "expression": "setTimeout(testFunction, 0)" });
var topFrameId;
function debuggerPaused(messageObject)
{
InspectorTest.log("Paused on 'debugger;'");
topFrameId = messageObject.params.callFrames[0].callFrameId;
Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: "f()"}).then(evaluatedFirst);
}
function evaluatedFirst(response)
{
InspectorTest.log("f() returns " + response.result.result.value);
Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: "g()"}).then(evaluatedSecond);
}
function evaluatedSecond(response)
{
InspectorTest.log("g() returns " + response.result.result.value);
Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: "f()", throwOnSideEffect: true}).then(evaluatedThird);
}
function evaluatedThird(response)
{
InspectorTest.log("f() returns " + response.result.result.value);
Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: "g()", throwOnSideEffect: true}).then(evaluatedFourth);
InspectorTest.completeTest();
}
function evaluatedFourth(response)
{
InspectorTest.log("g() throws " + response.result.result.className);
InspectorTest.completeTest();
}
InspectorTest.runAsyncTestSuite([
async function basicTest() {
Protocol.Debugger.enable();
Protocol.Runtime.evaluate({ 'expression': 'setTimeout(testFunction, 0)' });
const {params:{callFrames:[{callFrameId: topFrameId}]}} = await Protocol.Debugger.oncePaused();
InspectorTest.log('Paused on "debugger;"');
const {result:{result:{value: fResult}}} = await Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: 'f()' });
InspectorTest.log('f() returns ' + fResult);
const {result:{result:{value: gResult}}} = await Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: 'g()' });
InspectorTest.log('g() returns ' + gResult);
const {result:{result:{value: fResultSideEffect}}} = await Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: 'f()', throwOnSideEffect: true});
InspectorTest.log('f() returns ' + fResultSideEffect);
const {result:{result:{className}}} = await Protocol.Debugger.evaluateOnCallFrame({ callFrameId: topFrameId, expression: 'g()', throwOnSideEffect: true});
InspectorTest.log('g() throws ' + className);
},
async function testDate() {
const check = async (expression) => {
const {result:{exceptionDetails}} = await Protocol.Runtime.evaluate({expression, throwOnSideEffect: true});
InspectorTest.log(expression + ' : ' + (exceptionDetails ? 'throws' : 'ok'));
};
// setters are only ok on temporary objects
await check('someGlobalDate.setDate(10)');
await check('new Date().setDate(10)');
await check('someGlobalDate.setFullYear(1991)');
await check('new Date().setFullYear(1991)');
await check('someGlobalDate.setHours(0)');
await check('new Date().setHours(0)');
// getters are ok on any Date
await check('someGlobalDate.getDate()');
await check('new Date().getDate()');
await check('someGlobalDate.getFullYear()');
await check('new Date().getFullYear()');
await check('someGlobalDate.getHours()');
await check('new Date().getHours()');
}
]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment