Commit 4eb41bf3 authored by Erik Luo's avatar Erik Luo Committed by Commit Bot

Whitelist common, side-effect-free IDL callbacks

Marks common callbacks that do not produce JS-observable side-effects
on: Document, DOMTokenList, Element, Node, Window, HTMLElement.

Note that several Window properties are lazy and need extra V8 support
to be whitelisted.

Bug: 829571
Change-Id: I9ad50c1ca9b8c260ec898bc94423286c142d6bec
Reviewed-on: https://chromium-review.googlesource.com/1024863Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Commit-Queue: Erik Luo <luoe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553672}
parent 5e8b57ed
......@@ -17,6 +17,10 @@ Expression `document.body`
has side effect: false, expected: false
Expression `document.head`
has side effect: false, expected: false
Expression `document.location`
has side effect: false, expected: false
Expression `document.defaultView`
has side effect: false, expected: false
Expression `document.activeElement`
has side effect: false, expected: false
Expression `div.tagName`
......@@ -25,6 +29,22 @@ Expression `div.id`
has side effect: false, expected: false
Expression `div.className`
has side effect: false, expected: false
Expression `div.classList`
has side effect: false, expected: false
Expression `div.attributes`
has side effect: false, expected: false
Expression `shadowContainer.shadowRoot`
has side effect: false, expected: false
Expression `div.innerHTML`
has side effect: false, expected: false
Expression `div.outerHTML`
has side effect: false, expected: false
Expression `div.hidden`
has side effect: false, expected: false
Expression `div.tabIndex`
has side effect: false, expected: false
Expression `div.style`
has side effect: false, expected: false
Expression `div.nodeType`
has side effect: false, expected: false
Expression `div.nodeName`
......@@ -49,6 +69,8 @@ Expression `div.previousSibling`
has side effect: false, expected: false
Expression `div.nextSibling`
has side effect: false, expected: false
Expression `div.ownerDocument`
has side effect: false, expected: false
Expression `document.nodeType`
has side effect: false, expected: false
Expression `document.nodeName`
......@@ -73,6 +95,8 @@ Expression `document.previousSibling`
has side effect: false, expected: false
Expression `document.nextSibling`
has side effect: false, expected: false
Expression `document.ownerDocument`
has side effect: false, expected: false
Expression `textNode.nodeType`
has side effect: false, expected: false
Expression `textNode.nodeName`
......@@ -97,6 +121,8 @@ Expression `textNode.previousSibling`
has side effect: false, expected: false
Expression `textNode.nextSibling`
has side effect: false, expected: false
Expression `textNode.ownerDocument`
has side effect: false, expected: false
Expression `div.childElementCount`
has side effect: false, expected: false
Expression `div.children`
......@@ -127,4 +153,16 @@ Expression `screenX`
has side effect: false, expected: false
Expression `screenY`
has side effect: false, expected: false
Expression `document`
has side effect: false, expected: false
Expression `history`
has side effect: false, expected: false
Expression `navigator`
has side effect: false, expected: false
Expression `performance`
has side effect: false, expected: false
Expression `window`
has side effect: true, expected: true
Expression `window.location`
has side effect: true, expected: true
......@@ -6,10 +6,19 @@
var div = document.createElement('div');
div.id = 'foo';
div.className = 'bar baz';
div.setAttribute('attr1', 'attr1-value');
div.tabIndex = -1;
div.style.color = 'red';
var textNode = document.createTextNode('footext');
div.appendChild(textNode);
var textNode2 = document.createTextNode('bartext');
div.appendChild(textNode2);
var shadowContainer = document.createElement('div');
var shadowRoot = shadowContainer.attachShadow({mode: 'open'});
var divInShadow = document.createElement('div');
shadowRoot.appendChild(divInShadow);
`);
// Sanity check: test that setters are not allowed on whitelisted accessors.
......@@ -24,6 +33,8 @@
await checkHasNoSideEffect(`document.scrollingElement`);
await checkHasNoSideEffect(`document.body`);
await checkHasNoSideEffect(`document.head`);
await checkHasNoSideEffect(`document.location`);
await checkHasNoSideEffect(`document.defaultView`);
// DocumentOrShadowRoot
await checkHasNoSideEffect(`document.activeElement`);
......@@ -32,6 +43,16 @@
await checkHasNoSideEffect(`div.tagName`);
await checkHasNoSideEffect(`div.id`);
await checkHasNoSideEffect(`div.className`);
await checkHasNoSideEffect(`div.classList`);
await checkHasNoSideEffect(`div.attributes`);
await checkHasNoSideEffect(`shadowContainer.shadowRoot`);
await checkHasNoSideEffect(`div.innerHTML`);
await checkHasNoSideEffect(`div.outerHTML`);
// HTMLElement
await checkHasNoSideEffect(`div.hidden`);
await checkHasNoSideEffect(`div.tabIndex`);
await checkHasNoSideEffect(`div.style`);
// Node
var testNodes = ['div', 'document', 'textNode'];
......@@ -48,6 +69,7 @@
await checkHasNoSideEffect(`${node}.lastChild`);
await checkHasNoSideEffect(`${node}.previousSibling`);
await checkHasNoSideEffect(`${node}.nextSibling`);
await checkHasNoSideEffect(`${node}.ownerDocument`);
}
// ParentNode
......@@ -62,6 +84,14 @@
await checkHasNoSideEffect(`devicePixelRatio`);
await checkHasNoSideEffect(`screenX`);
await checkHasNoSideEffect(`screenY`);
await checkHasNoSideEffect(`document`);
await checkHasNoSideEffect(`history`);
await checkHasNoSideEffect(`navigator`);
await checkHasNoSideEffect(`performance`);
// TODO(luoe): add support for LazyData properties.
await checkHasSideEffect(`window`);
await checkHasSideEffect(`window.location`);
testRunner.completeTest();
......
......@@ -27,12 +27,22 @@ Expression `unmonitorEvents.toString()`
has side effect: false, expected: false
Expression `document.getElementsByTagName('div')`
has side effect: false, expected: false
Expression `document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'div')`
Expression `document.getElementsByTagNameNS(namespace, 'div')`
has side effect: false, expected: false
Expression `document.getElementsByClassName('foo')`
has side effect: false, expected: false
Expression `document.getElementsByName('div-name')`
has side effect: false, expected: false
Expression `document.hasFocus()`
has side effect: false, expected: false
Expression `document.getSelection()`
has side effect: false, expected: false
Expression `domTokenList.contains('foo')`
has side effect: false, expected: false
Expression `domTokenList.contains({})`
has side effect: false, expected: false
Expression `domTokenList.contains()`
has side effect: false, expected: false
Expression `div.getAttributeNames()`
has side effect: false, expected: false
Expression `divNoAttrs.getAttributeNames()`
......@@ -53,6 +63,26 @@ Expression `div.hasAttribute({})`
has side effect: false, expected: false
Expression `divNoAttrs.hasAttribute('attr1')`
has side effect: false, expected: false
Expression `div.getAttributeNS(namespace, 'attr1')`
has side effect: false, expected: false
Expression `div.getAttributeNS(namespace)`
has side effect: false, expected: false
Expression `div.getAttributeNS()`
has side effect: false, expected: false
Expression `divNoAttrs.getAttributeNS(namespace, 'attr1')`
has side effect: false, expected: false
Expression `div.hasAttributeNS(namespace, 'attr1')`
has side effect: false, expected: false
Expression `div.hasAttributeNS(namespace)`
has side effect: false, expected: false
Expression `div.hasAttributeNS()`
has side effect: false, expected: false
Expression `divNoAttrs.hasAttributeNS(namespace, 'attr1')`
has side effect: false, expected: false
Expression `divNoAttrs.hasAttributeNS(namespace)`
has side effect: false, expected: false
Expression `div.hasAttributes()`
has side effect: false, expected: false
Expression `div.contains(textNode)`
has side effect: false, expected: false
Expression `div.contains()`
......@@ -63,6 +93,8 @@ Expression `div.querySelector('div')`
has side effect: false, expected: false
Expression `div.querySelectorAll('div')`
has side effect: false, expected: false
Expression `div.hasChildNodes()`
has side effect: false, expected: false
Expression `document.contains(textNode)`
has side effect: false, expected: false
Expression `document.contains()`
......@@ -73,6 +105,8 @@ Expression `document.querySelector('div')`
has side effect: false, expected: false
Expression `document.querySelectorAll('div')`
has side effect: false, expected: false
Expression `document.hasChildNodes()`
has side effect: false, expected: false
Expression `textNode.contains(textNode)`
has side effect: false, expected: false
Expression `textNode.contains()`
......@@ -83,7 +117,11 @@ Expression `textNode.querySelector('div')`
has side effect: false, expected: false
Expression `textNode.querySelectorAll('div')`
has side effect: false, expected: false
Expression `global_performance.now()`
Expression `textNode.hasChildNodes()`
has side effect: false, expected: false
Expression `performance.now()`
has side effect: false, expected: false
Expression `global_getSelection()`
has side effect: false, expected: false
Expression `htmlCollection[0]`
has side effect: false, expected: false
......
......@@ -3,9 +3,10 @@
`Tests that evaluating V8-embedder callbacks allows side-effect-free methods. Should not crash.`);
await session.evaluate(`
var global_performance = window.performance;
var global_getSelection = window.getSelection;
document.documentElement.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
var namespace = 'http://www.w3.org/1999/xhtml';
document.documentElement.setAttribute('xmlns', namespace);
var div = document.createElement('div');
div.setAttribute('attr1', 'attr1-value');
......@@ -52,9 +53,18 @@
// Document
await checkHasNoSideEffect(`document.getElementsByTagName('div')`);
await checkHasNoSideEffect(`document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'div')`);
await checkHasNoSideEffect(`document.getElementsByTagNameNS(namespace, 'div')`);
await checkHasNoSideEffect(`document.getElementsByClassName('foo')`);
await checkHasNoSideEffect(`document.getElementsByName('div-name')`);
await checkHasNoSideEffect(`document.hasFocus()`);
// DocumentOrShadowRoot
await checkHasNoSideEffect(`document.getSelection()`);
// DOMTokenList
await checkHasNoSideEffect(`domTokenList.contains('foo')`);
await checkHasNoSideEffect(`domTokenList.contains({})`);
await checkHasNoSideEffect(`domTokenList.contains()`);
// Element
await checkHasNoSideEffect(`div.getAttributeNames()`);
......@@ -68,6 +78,18 @@
await checkHasNoSideEffect(`div.hasAttribute({})`);
await checkHasNoSideEffect(`divNoAttrs.hasAttribute('attr1')`);
await checkHasNoSideEffect(`div.getAttributeNS(namespace, 'attr1')`);
await checkHasNoSideEffect(`div.getAttributeNS(namespace)`);
await checkHasNoSideEffect(`div.getAttributeNS()`);
await checkHasNoSideEffect(`divNoAttrs.getAttributeNS(namespace, 'attr1')`);
await checkHasNoSideEffect(`div.hasAttributeNS(namespace, 'attr1')`);
await checkHasNoSideEffect(`div.hasAttributeNS(namespace)`);
await checkHasNoSideEffect(`div.hasAttributeNS()`);
await checkHasNoSideEffect(`divNoAttrs.hasAttributeNS(namespace, 'attr1')`);
await checkHasNoSideEffect(`divNoAttrs.hasAttributeNS(namespace)`);
await checkHasNoSideEffect(`div.hasAttributes()`);
// Node
var testNodes = ['div', 'document', 'textNode'];
for (var node of testNodes) {
......@@ -76,10 +98,14 @@
await checkHasNoSideEffect(`${node}.contains({})`);
await checkHasNoSideEffect(`${node}.querySelector('div')`);
await checkHasNoSideEffect(`${node}.querySelectorAll('div')`);
await checkHasNoSideEffect(`${node}.hasChildNodes()`);
}
// Performance
await checkHasNoSideEffect(`performance.now()`);
// Window
await checkHasNoSideEffect(`global_performance.now()`);
await checkHasNoSideEffect(`global_getSelection()`);
// Collection getters (e.g. HTMLCollection, NodeList)
var indexedCollections = [
......
......@@ -92,7 +92,7 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
// resource metadata management
[PutForwards=href, Unforgeable] readonly attribute Location? location;
[Affects=Nothing, PutForwards=href, Unforgeable] readonly attribute Location? location;
[Affects=Nothing, RaisesException=Setter] attribute USVString domain;
[Affects=Nothing] readonly attribute USVString referrer;
[Affects=Nothing, RaisesException, RuntimeCallStatsCounter=DocumentCookie] attribute DOMString cookie;
......@@ -129,8 +129,8 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
[RuntimeEnabled=TrustedDOMTypes, CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void writeln(TrustedHTML text);
// user interaction
readonly attribute Window? defaultView;
boolean hasFocus();
[Affects=Nothing] readonly attribute Window? defaultView;
[Affects=Nothing] boolean hasFocus();
[CEReactions, CustomElementCallbacks, MeasureAs=DocumentDesignMode] attribute DOMString designMode;
[CEReactions, CustomElementCallbacks, RaisesException] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = "");
[RaisesException] boolean queryCommandEnabled(DOMString commandId);
......
......@@ -10,7 +10,7 @@
] interface DocumentOrShadowRoot {
// Selection API
// https://w3c.github.io/selection-api/#extensions-to-document-interface
Selection? getSelection();
[Affects=Nothing] Selection? getSelection();
// CSSOM View Module
// https://drafts.csswg.org/cssom-view/#extensions-to-the-document-interface
Element? elementFromPoint(double x, double y);
......
......@@ -30,7 +30,7 @@
] interface DOMTokenList {
[Affects=Nothing] readonly attribute unsigned long length;
[Affects=Nothing] getter DOMString? item(unsigned long index);
boolean contains(DOMString token);
[Affects=Nothing] boolean contains(DOMString token);
[RaisesException, CEReactions, CustomElementCallbacks] void add(DOMString... tokens);
[RaisesException, CEReactions, CustomElementCallbacks] void remove(DOMString... tokens);
[RaisesException, CEReactions, CustomElementCallbacks] boolean toggle(DOMString token, optional boolean force);
......
......@@ -34,7 +34,7 @@ interface Element : Node {
[Affects=Nothing, CEReactions, Reflect] attribute DOMString id;
[Affects=Nothing, CEReactions, Reflect=class] attribute DOMString className;
[SameObject, PerWorldBindings, PutForwards=value] readonly attribute DOMTokenList classList;
[Affects=Nothing, SameObject, PerWorldBindings, PutForwards=value] readonly attribute DOMTokenList classList;
[Unscopable, CEReactions, Reflect] attribute DOMString slot;
// Pointer Events
......@@ -43,17 +43,17 @@ interface Element : Node {
[RaisesException] void releasePointerCapture (long pointerId);
boolean hasPointerCapture (long pointerId);
boolean hasAttributes();
[SameObject, PerWorldBindings, ImplementedAs=attributesForBindings] readonly attribute NamedNodeMap attributes;
[Affects=Nothing] boolean hasAttributes();
[Affects=Nothing, SameObject, PerWorldBindings, ImplementedAs=attributesForBindings] readonly attribute NamedNodeMap attributes;
[Affects=Nothing] sequence<DOMString> getAttributeNames();
[Affects=Nothing] DOMString? getAttribute(DOMString name);
DOMString? getAttributeNS(DOMString? namespaceURI, DOMString localName);
[Affects=Nothing] DOMString? getAttributeNS(DOMString? namespaceURI, DOMString localName);
[RaisesException, CEReactions, CustomElementCallbacks] void setAttribute(DOMString name, DOMString value);
[RaisesException, CEReactions, CustomElementCallbacks] void setAttributeNS(DOMString? namespaceURI, DOMString name, DOMString value);
[CEReactions, CustomElementCallbacks] void removeAttribute(DOMString name);
[CEReactions, CustomElementCallbacks] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
[Affects=Nothing] boolean hasAttribute(DOMString name);
boolean hasAttributeNS(DOMString? namespaceURI, DOMString localName);
[Affects=Nothing] boolean hasAttributeNS(DOMString? namespaceURI, DOMString localName);
Attr? getAttributeNode(DOMString name);
Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
......@@ -66,7 +66,7 @@ interface Element : Node {
[RaisesException, ImplementedAs=matches, MeasureAs=ElementPrefixedMatchesSelector] boolean webkitMatchesSelector(DOMString selectors); // historical alias of .matches
[RaisesException, CallWith=ScriptState, MeasureAs=ElementAttachShadow] ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
[PerWorldBindings, ImplementedAs=OpenShadowRoot] readonly attribute ShadowRoot? shadowRoot;
[Affects=Nothing, PerWorldBindings, ImplementedAs=OpenShadowRoot] readonly attribute ShadowRoot? shadowRoot;
[Affects=Nothing] HTMLCollection getElementsByTagName(DOMString localName);
[Affects=Nothing] HTMLCollection getElementsByTagNameNS(DOMString? namespaceURI, DOMString localName);
......@@ -83,8 +83,8 @@ interface Element : Node {
// https://w3c.github.io/DOM-Parsing/#extensions-to-the-element-interface
//
// TODO(mkwst): Write a spec for the `TrustedHTML` variants.
[CEReactions, CustomElementCallbacks, Custom=Setter, RuntimeCallStatsCounter=ElementInnerHTML] attribute HTMLString innerHTML;
[CEReactions, CustomElementCallbacks, Custom=Setter] attribute HTMLString outerHTML;
[Affects=Nothing, CEReactions, CustomElementCallbacks, Custom=Setter, RuntimeCallStatsCounter=ElementInnerHTML] attribute HTMLString innerHTML;
[Affects=Nothing, CEReactions, CustomElementCallbacks, Custom=Setter] attribute HTMLString outerHTML;
[CEReactions, CustomElementCallbacks, RaisesException] void insertAdjacentHTML(DOMString position, HTMLString text);
// Pointer Lock
......
......@@ -39,10 +39,10 @@ interface Node : EventTarget {
readonly attribute USVString baseURI;
[Affects=Nothing, Measure] readonly attribute boolean isConnected;
[PerWorldBindings] readonly attribute Document? ownerDocument;
[Affects=Nothing, PerWorldBindings] readonly attribute Document? ownerDocument;
[Affects=Nothing, PerWorldBindings] readonly attribute Node? parentNode;
[Affects=Nothing, PerWorldBindings] readonly attribute Element? parentElement;
[ImplementedAs=hasChildren] boolean hasChildNodes();
[Affects=Nothing, ImplementedAs=hasChildren] boolean hasChildNodes();
[Affects=Nothing, SameObject, PerWorldBindings] readonly attribute NodeList childNodes;
[Affects=Nothing, PerWorldBindings] readonly attribute Node? firstChild;
[Affects=Nothing, PerWorldBindings] readonly attribute Node? lastChild;
......
......@@ -36,11 +36,11 @@
// FIXME: The spec uses the WindowProxy type for this and many other attributes.
[Unforgeable, CrossOrigin] readonly attribute Window window;
[Replaceable, CrossOrigin] readonly attribute Window self;
[Unforgeable, CachedAccessor] readonly attribute Document document;
[Affects=Nothing, Unforgeable, CachedAccessor] readonly attribute Document document;
[Replaceable] readonly attribute DOMString origin;
attribute DOMString name;
[PutForwards=href, Unforgeable, CrossOrigin=(Getter,Setter), Custom=Getter] readonly attribute Location location;
readonly attribute History history;
[Affects=Nothing] readonly attribute History history;
[Replaceable, MeasureAs=BarPropLocationbar] readonly attribute BarProp locationbar;
[Replaceable, MeasureAs=BarPropMenubar] readonly attribute BarProp menubar;
[Replaceable, MeasureAs=BarPropPersonalbar] readonly attribute BarProp personalbar;
......@@ -84,7 +84,7 @@
[Custom, NotEnumerable, CrossOrigin] getter object (DOMString name);
// the user agent
[LogActivity=GetterOnly] readonly attribute Navigator navigator;
[Affects=Nothing, LogActivity=GetterOnly] readonly attribute Navigator navigator;
[LogActivity=GetterOnly, SecureContext=RestrictAppCacheToSecureContexts] readonly attribute ApplicationCache applicationCache;
// user prompts
......@@ -157,7 +157,7 @@
// Selection API
// https://w3c.github.io/selection-api/#extensions-to-window-interface
Selection? getSelection();
[Affects=Nothing] Selection? getSelection();
// Console API
// https://console.spec.whatwg.org/#console-interface
......
......@@ -29,9 +29,9 @@ interface HTMLElement : Element {
[SameObject, PerWorldBindings] readonly attribute DOMStringMap dataset;
// user interaction
[CEReactions, Reflect] attribute boolean hidden;
[Affects=Nothing, CEReactions, Reflect] attribute boolean hidden;
[RuntimeCallStatsCounter=HTMLElementClick] void click();
[CEReactions, CustomElementCallbacks] attribute long tabIndex;
[Affects=Nothing, CEReactions, CustomElementCallbacks] attribute long tabIndex;
[CEReactions, RuntimeEnabled=InertAttribute, Reflect] attribute boolean inert;
void focus(optional FocusOptions options);
void blur();
......@@ -56,7 +56,7 @@ interface HTMLElement : Element {
// CSS Object Model (CSSOM)
// https://drafts.csswg.org/cssom/#the-elementcssinlinestyle-interface
[SameObject, PerWorldBindings, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
[Affects=Nothing, SameObject, PerWorldBindings, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
// Non-standard APIs
[CEReactions, CustomElementCallbacks, RaisesException=Setter, MeasureAs=HTMLElementInnerText] attribute [TreatNullAs=NullString] DOMString innerText;
......
......@@ -9,5 +9,5 @@
[
ImplementedAs=DOMWindowPerformance
] partial interface Window {
[Replaceable] readonly attribute Performance performance;
[Affects=Nothing, Replaceable] readonly attribute Performance performance;
};
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