Commit 36ebfbe5 authored by Marina Sakai's avatar Marina Sakai Committed by Commit Bot

Stop using private properties for data properties of cross-origin properties

Since Blink properly supports the incumbent realm now, there is no more need to use OriginSafeMethodSetter, which sets value via V8PrivateProperty.
So there is no need to use V8PrivateProperty also in OriginSafeMethodGetter.

This CL makes it possible to handle "data properties" of cross-origin properties as the proper data properties.


Bug: 715418
Change-Id: I336a8459b80bc63d08a248f3ed7a34dc0806e5ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1844520
Commit-Queue: Marina Sakai <marinasakai@google.com>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706304}
parent 00bd6c8a
......@@ -80,7 +80,6 @@ class InterfaceTemplateContextBuilder(object):
has_cross_origin_named_enum = False
has_cross_origin_named_getter = False
has_cross_origin_named_setter = False
has_origin_safe_method_setter = False
has_security_check = False
indexed_property_getter = None
is_global = False
......@@ -98,9 +97,6 @@ class InterfaceTemplateContextBuilder(object):
interface.indexed_property_getter, ['index'])
if not interface.is_partial:
has_origin_safe_method_setter = is_global and any(
method['is_check_security_for_receiver'] and not method['is_unforgeable']
for method in methods)
has_security_check = ('CheckSecurity' in interface.extended_attributes and
interface.name != 'EventTarget')
has_cross_origin_named_getter = (any(method['is_cross_origin'] for method in methods) or
......@@ -114,7 +110,6 @@ class InterfaceTemplateContextBuilder(object):
return {
'attributes': attributes,
'component': component,
'has_origin_safe_method_setter': has_origin_safe_method_setter,
'has_constructor_callback': has_constructor_callback,
'has_cross_origin_named_getter': has_cross_origin_named_getter,
'has_cross_origin_named_setter': has_cross_origin_named_setter,
......
......@@ -434,10 +434,6 @@ def interface_context(interface, interfaces, component_info):
# Methods
context.update(methods_context(interface, component_info))
methods = context['methods']
context.update({
'has_origin_safe_method_setter': any(method['is_cross_origin'] and not method['is_unforgeable']
for method in methods),
})
# Conditionally enabled methods
conditional_methods = v8_methods.filter_conditionally_enabled(methods, interface.is_partial)
......
......@@ -58,9 +58,6 @@ const intptr_t* {{class}}::GetTable() {
{% endif%}
{% endfor %}
{% endfor %}{# method #}
{% if interface.has_origin_safe_method_setter %}
reinterpret_cast<intptr_t>({{v8_class}}::{{interface.name}}OriginSafeMethodSetterCallback),
{% endif %}
{% if interface.has_cross_origin_named_getter %}
reinterpret_cast<intptr_t>({{v8_class}}::CrossOriginNamedGetter),
{% endif %}
......
......@@ -721,58 +721,6 @@ void {{v8_class_or_partial}}::NamedPropertyEnumeratorCallback(
{% endblock %}
{##############################################################################}
{# TODO(dcheng): Currently, bindings must create a function object for each
realm as a hack to support the incumbent realm. Remove this when Blink
properly supports the incumbent realm. #}
{% block origin_safe_method_setter %}
{% if has_origin_safe_method_setter %}
static void {{cpp_class}}OriginSafeMethodSetter(
v8::Local<v8::Name> name,
v8::Local<v8::Value> v8_value,
const v8::PropertyCallbackInfo<void>& info) {
if (!name->IsString())
return;
v8::Local<v8::Object> holder =
{{v8_class}}::FindInstanceInPrototypeChain(info.Holder(), info.GetIsolate());
if (holder.IsEmpty())
return;
{{cpp_class}}* impl = {{v8_class}}::ToImpl(holder);
v8::String::Utf8Value name_in_utf8(info.GetIsolate(), name);
ExceptionState exception_state(
info.GetIsolate(),
ExceptionState::kSetterContext,
"{{interface_name}}",
*name_in_utf8);
if (!BindingSecurity::ShouldAllowAccessTo(
CurrentDOMWindow(info.GetIsolate()), impl, exception_state)) {
return;
}
{# The findInstanceInPrototypeChain() call above only returns a non-empty handle if info.Holder() is an Object. #}
{% raw %}
// |methodName| must be same with {{method.name}} in
// {{method.name}}OriginSafeMethodGetter{{world_suffix}} defined in
// methods.cc.tmpl
{% endraw %}
V8PrivateProperty::GetSymbol(info.GetIsolate(), *name_in_utf8)
.Set(v8::Local<v8::Object>::Cast(info.Holder()), v8_value);
}
{% endif %}
{% endblock %}
{% block origin_safe_method_setter_callback %}
{% if has_origin_safe_method_setter %}
void {{v8_class_or_partial}}::{{cpp_class}}OriginSafeMethodSetterCallback(
v8::Local<v8::Name> name,
v8::Local<v8::Value> v8_value,
const v8::PropertyCallbackInfo<void>& info) {
{{internal_namespace}}::{{cpp_class}}OriginSafeMethodSetter(name, v8_value, info);
}
{% endif %}
{% endblock %}
{##############################################################################}
{% block named_constructor %}
{% from 'methods.cc.tmpl' import generate_constructor with context %}
......@@ -954,64 +902,58 @@ static void Constructor(const v8::FunctionCallbackInfo<v8::Value>& info) {
{##############################################################################}
{% macro install_origin_safe_method(method, instance_template, prototype_template) %}
{% macro install_origin_safe_method(method, instance_template, prototype_template, interface_template, signature) %}
{% from 'utilities.cc.tmpl' import property_location %}
{# TODO(dcheng): Currently, bindings must create a function object for each
realm as a hack to support the incumbent realm. Clean this up when Blink
properly supports the incumbent realm. #}
{% set getter_callback =
'%s::%sOriginSafeMethodGetterCallback' %
(v8_class_or_partial, method.camel_case_name) %}
{% set setter_callback =
'%s::%sOriginSafeMethodSetterCallback' % (v8_class_or_partial, cpp_class)
if not method.is_unforgeable else 'nullptr' %}
{% set function_callback =
'%s::%sMethodCallback' % (v8_class_or_partial, method.camel_case_name) %}
{% set property_attribute =
'static_cast<v8::PropertyAttribute>(%s)' %
' | '.join(method.property_attributes or ['v8::None']) %}
{% set holder_check = 'V8DOMConfiguration::kCheckHolder' %}
static const V8DOMConfiguration::AttributeConfiguration {{method.name}}OriginSafeAttributeConfiguration[] = {
static const V8DOMConfiguration::MethodConfiguration k{{method.camel_case_name}}OriginSafeMethodConfiguration[] = {
{% if method.is_per_world_bindings %}
{% set getter_callback_for_main_world = '%sForMainWorld' % getter_callback %}
{% set setter_callback_for_main_world = '%sForMainWorld' % setter_callback
if not method.is_unforgeable else 'nullptr' %}
{% set function_callback_for_main_world = '%sForMainWorld' % function_callback %}
{
"{{method.name}}",
{{getter_callback_for_main_world}},
{{setter_callback_for_main_world}},
{{function_callback_for_main_world}},
{{method.length}},
{{property_attribute}},
{{property_location(method)}},
{{holder_check}},
V8DOMConfiguration::kCheckAccess,
V8DOMConfiguration::kHasSideEffect,
V8DOMConfiguration::kAlwaysCallGetter,
V8DOMConfiguration::MainWorld,
},
{
"{{method.name}}",
{{getter_callback}},
{{setter_callback}},
{{function_callback}},
{{method.length}},
{{property_attribute}},
{{property_location(method)}},
{{holder_check}},
V8DOMConfiguration::kCheckAccess,
V8DOMConfiguration::kHasSideEffect,
V8DOMConfiguration::kAlwaysCallGetter,
V8DOMConfiguration::NonMainWorlds,
}
{% else %}
{
"{{method.name}}",
{{getter_callback}},
{{setter_callback}},
{{function_callback}},
{{method.length}},
{{property_attribute}},
{{property_location(method)}},
{{holder_check}},
V8DOMConfiguration::kCheckAccess,
V8DOMConfiguration::kHasSideEffect,
V8DOMConfiguration::kAlwaysCallGetter,
V8DOMConfiguration::kAllWorlds,
}
{% endif %}
};
for (const auto& attributeConfig : {{method.name}}OriginSafeAttributeConfiguration)
V8DOMConfiguration::InstallAttribute(isolate, world, {{instance_template}}, {{prototype_template}}, attributeConfig);
for (const auto& method_config : k{{method.camel_case_name}}OriginSafeMethodConfiguration)
V8DOMConfiguration::InstallMethod(isolate, world, {{instance_template}}, {{prototype_template}}, {{interface_template}}, {{signature}}, method_config);
{%- endmacro %}
......
......@@ -220,9 +220,6 @@ class {{v8_class}} {
{% if iterator_method %}
{{exported}}static void {{iterator_method.camel_case_name}}MethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
{% endif %}
{% if has_origin_safe_method_setter %}
{{exported}}static void {{cpp_class}}OriginSafeMethodSetterCallback(v8::Local<v8::Name>, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&);
{% endif %}
{% if has_access_check_callbacks and not is_partial %}
{{exported}}static bool SecurityCheck(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>);
......
......@@ -128,7 +128,6 @@ static void (*{{method.name}}MethodForPartialInterface)(const v8::FunctionCallba
{% if iterator_method %}
{{generate_method(iterator_method)}}
{% endif %}
{% block origin_safe_method_setter %}{% endblock %}
{# Constructors #}
{% for constructor in constructors %}
{{generate_constructor(constructor)}}
......@@ -235,7 +234,6 @@ static const struct {
{% if iterator_method %}
{{method_callback(iterator_method)}}
{% endif %}
{% block origin_safe_method_setter_callback %}{% endblock %}
{# Special operations (methods) #}
{% block named_property_getter_callback %}{% endblock %}
{% block named_property_setter_callback %}{% endblock %}
......@@ -616,7 +614,7 @@ static void Install{{v8_class}}Template(
if method.overloads else method.runtime_enabled_feature_name %}
{% if not feature_name %}
{% if method.is_cross_origin %}
{{install_origin_safe_method(method, 'instance_template', 'prototype_template') | trim | indent(2)}}
{{install_origin_safe_method(method, 'instance_template', 'prototype_template', 'interface_template', 'signature') | trim | indent(2)}}
{% else %}
{{install_custom_signature(method, 'instance_template', 'prototype_template', 'interface_template', 'signature') | trim | indent(2)}}
{% endif %}
......
......@@ -516,32 +516,7 @@ static void {{method.camel_case_name}}OriginSafeMethodGetter{{world_suffix}}(con
v8::Local<v8::Signature> signature =
v8::Signature::New(isolate, interface_template);
{{cpp_class}}* impl = {{v8_class}}::ToImpl(info.Holder());
// Different FunctionTemplates should be used between cross-origin access and
// same-origin access.
if (!BindingSecurity::ShouldAllowAccessTo(
CurrentDOMWindow(isolate), impl,
BindingSecurity::ErrorReportOption::kDoNotReport)) {
static int dom_template_key; // This address is used for a key to look up the dom template.
v8::Local<v8::FunctionTemplate> method_template =
data->FindOrCreateOperationTemplate(
world,
&dom_template_key,
{{v8_class_or_partial}}::{{method.camel_case_name}}MethodCallback{{world_suffix}},
v8::Local<v8::Value>(),
signature,
{{method.length}});
V8SetReturnValue(
info,
method_template->GetFunction(
isolate->GetCurrentContext()).ToLocalChecked());
return;
}
static int dom_template_key; // This address is used for a key to look up the dom template.
v8::Local<v8::FunctionTemplate> method_template =
data->FindOrCreateOperationTemplate(
world,
......@@ -551,21 +526,10 @@ static void {{method.camel_case_name}}OriginSafeMethodGetter{{world_suffix}}(con
signature,
{{method.length}});
// When the web author overwrote the property, return the overwriting value.
//
// "{{method.name}}" must be the same as |name_in_utf8| (=name) in
// {{cpp_class}}OriginSafeMethodSetter defined in interface.cc.tmpl.
V8PrivateProperty::Symbol property_symbol =
V8PrivateProperty::GetSymbol(isolate, "{{method.name}}");
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast(info.Holder());
if (property_symbol.HasValue(holder)) {
V8SetReturnValue(info, property_symbol.GetOrUndefined(holder));
} else {
V8SetReturnValue(
info,
method_template->GetFunction(
holder->CreationContext()).ToLocalChecked());
}
V8SetReturnValue(
info,
method_template->GetFunction(
isolate->GetCurrentContext()).ToLocalChecked());
}
{% endmacro %}
......
......@@ -100,9 +100,6 @@ class {{v8_class_or_partial}} {
{% if iterator_method %}
{{exported}}static void {{iterator_method.camel_case_name}}MethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
{% endif %}
{% if has_origin_safe_method_setter %}
{{exported}}static void {{cpp_class}}OriginSafeMethodSetterCallback(v8::Local<v8::Name> name, v8::Local<v8::Value> v8_value, const v8::PropertyCallbackInfo<void>& info);
{% endif %}
private:
{% if needs_runtime_enabled_installer %}
......
......@@ -75,7 +75,6 @@ class V8TestInterfaceCheckSecurity {
CORE_EXPORT static void DoNotCheckSecurityVoidOverloadMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
CORE_EXPORT static void DoNotCheckSecurityVoidOverloadMethodOriginSafeMethodGetterCallback(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>&);
CORE_EXPORT static void SecureContextRuntimeEnabledMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
CORE_EXPORT static void TestInterfaceCheckSecurityOriginSafeMethodSetterCallback(v8::Local<v8::Name>, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&);
CORE_EXPORT static bool SecurityCheck(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>);
CORE_EXPORT static void CrossOriginNamedGetter(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>&);
......
......@@ -6,9 +6,9 @@ PASS Basic sanity-checking (cross-site)
FAIL Only whitelisted properties are accessible cross-origin (cross-origin) Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
FAIL Only whitelisted properties are accessible cross-origin (same-origin + document.domain) Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
FAIL Only whitelisted properties are accessible cross-origin (cross-site) Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
FAIL Only whitelisted properties are usable as cross-origin this objects (cross-origin) promise_test: Unhandled rejection with value: object "SecurityError: Failed to execute 'replace' on 'Location': The current window does not have permission to navigate the target frame to 'javascript:undefined'."
FAIL Only whitelisted properties are usable as cross-origin this objects (same-origin + document.domain) promise_test: Unhandled rejection with value: object "SecurityError: Failed to execute 'replace' on 'Location': The current window does not have permission to navigate the target frame to 'javascript:undefined'."
FAIL Only whitelisted properties are usable as cross-origin this objects (cross-site) promise_test: Unhandled rejection with value: object "SecurityError: Failed to execute 'replace' on 'Location': The current window does not have permission to navigate the target frame to 'javascript:undefined'."
FAIL Only whitelisted properties are usable as cross-origin this objects (cross-origin) promise_test: Unhandled rejection with value: object "SecurityError: Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame."
FAIL Only whitelisted properties are usable as cross-origin this objects (same-origin + document.domain) promise_test: Unhandled rejection with value: object "SecurityError: Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame."
FAIL Only whitelisted properties are usable as cross-origin this objects (cross-site) promise_test: Unhandled rejection with value: object "SecurityError: Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame."
PASS [[GetPrototypeOf]] should return null (cross-origin)
PASS [[GetPrototypeOf]] should return null (same-origin + document.domain)
PASS [[GetPrototypeOf]] should return null (cross-site)
......
......@@ -148,6 +148,9 @@ addTest(function(win) {
assert_throws("SecurityError", function() { win.location.pathname; }, "location.pathname throws cross-origin");
assert_equals(B.frames, 'override', "Overrides visible in the same-origin case");
assert_equals(win.frames, win, "Overrides invisible in the cross-origin case");
assert_equals(B.focus, 'override', "Overrides visible in the same-origin case");
checkFunction(win.focus, Function.prototype);
assert_not_equals(win.focus, focus, "Overrides invisible in the cross-origin case");
}, "Basic sanity-checking");
/*
......
......@@ -6,9 +6,10 @@
document.domain = document.domain;
}
// Override the |frames| property to test that such overrides are
// Override the |frames| and |focus| property to test that such overrides are
// properly ignored cross-origin.
window.frames = "override";
window.focus = "override";
// Also add a |then| property to test that it doesn't get exposed.
window.then = "something";
......
......@@ -9,8 +9,8 @@ PASS 'function alert() { [native code] }' is 'function alert() { [native code] }
PASS 'function alert() { [native code] }' is 'function alert() { [native code] }'
PASS 'function atob() { [native code] }' is 'function atob() { [native code] }'
PASS 'function atob() { [native code] }' is 'function atob() { [native code] }'
PASS 'function () { [native code] }' is 'function () { [native code] }'
PASS 'function () { [native code] }' is 'function () { [native code] }'
PASS 'function blur() { [native code] }' is 'function blur() { [native code] }'
PASS 'function blur() { [native code] }' is 'function blur() { [native code] }'
PASS 'function btoa() { [native code] }' is 'function btoa() { [native code] }'
PASS 'function btoa() { [native code] }' is 'function btoa() { [native code] }'
PASS 'function captureEvents() { [native code] }' is 'function captureEvents() { [native code] }'
......@@ -19,14 +19,14 @@ PASS 'function clearInterval() { [native code] }' is 'function clearInterval() {
PASS 'function clearInterval() { [native code] }' is 'function clearInterval() { [native code] }'
PASS 'function clearTimeout() { [native code] }' is 'function clearTimeout() { [native code] }'
PASS 'function clearTimeout() { [native code] }' is 'function clearTimeout() { [native code] }'
PASS 'function () { [native code] }' is 'function () { [native code] }'
PASS 'function () { [native code] }' is 'function () { [native code] }'
PASS 'function close() { [native code] }' is 'function close() { [native code] }'
PASS 'function close() { [native code] }' is 'function close() { [native code] }'
PASS 'function confirm() { [native code] }' is 'function confirm() { [native code] }'
PASS 'function confirm() { [native code] }' is 'function confirm() { [native code] }'
PASS 'function find() { [native code] }' is 'function find() { [native code] }'
PASS 'function find() { [native code] }' is 'function find() { [native code] }'
PASS 'function () { [native code] }' is 'function () { [native code] }'
PASS 'function () { [native code] }' is 'function () { [native code] }'
PASS 'function focus() { [native code] }' is 'function focus() { [native code] }'
PASS 'function focus() { [native code] }' is 'function focus() { [native code] }'
PASS 'function getComputedStyle() { [native code] }' is 'function getComputedStyle() { [native code] }'
PASS 'function getComputedStyle() { [native code] }' is 'function getComputedStyle() { [native code] }'
PASS 'function getSelection() { [native code] }' is 'function getSelection() { [native code] }'
......
......@@ -27,7 +27,7 @@ PASS Posting message ('[detached TypedArray]', ): threw exception DataCloneError
PASS Posting message ('data', [detached TypedArray]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 does not have a transferable type.
PASS Posting message ('data', [object Object]): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Iterator getter is not callable.
PASS Posting message ('data', 1,,2): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 does not have a transferable type.
PASS Posting message ('data', ,function () { [native code] }): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 is an untransferable 'null' value.
PASS Posting message ('data', ,function postMessage() { [native code] }): threw exception TypeError: Failed to execute 'postMessage' on 'Window': Value at index 0 is an untransferable 'null' value.
PASS window.postMessage() threw exception TypeError: Failed to execute 'postMessage' on 'Window': 1 argument required, but only 0 present..
PASS Posting message ('a', undefined): threw exception SyntaxError: Failed to execute 'postMessage' on 'Window': Invalid target origin 'undefined' in a call to 'postMessage'.
PASS Posting message ('done', undefined) did not throw an exception
......
......@@ -13,7 +13,7 @@ console-log-side-effects.js:33 Number {-4.242e-11}
console-log-side-effects.js:34 Boolean {true}
console-log-side-effects.js:35 String {"foo"}
console-log-side-effects.js:36 {}
console-log-side-effects.js:37 Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
console-log-side-effects.js:37 Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
console-log-side-effects.js:43
console-log-side-effects.js:47 {foo: 1, bar: 2}
console-log-side-effects.js:48 (3) [1, 2, 3]
......
----- tests for getting a targetWindow's functions which have custom overrides. The desired behavior is for the targetWindow to return the built-in function, not the override -----
PASS: canGet('targetWindow.focus') should be 'true' and is.
PASS: toString('targetWindow.focus') should be 'function () { [native code] }' and is.
PASS: targetWindow.focus.name should be '' and is.
PASS: canGet('targetWindow.blur') should be 'true' and is.
PASS: toString('targetWindow.blur') should be 'function () { [native code] }' and is.
PASS: targetWindow.blur.name should be '' and is.
PASS: canGet('targetWindow.close') should be 'true' and is.
PASS: toString('targetWindow.close') should be 'function () { [native code] }' and is.
PASS: targetWindow.close.name should be '' and is.
......@@ -16,15 +16,15 @@
// Overriden using window.focus = function() { return "new focus" }
shouldBeTrue("canGet('targetWindow.focus')");
shouldBe("toString('targetWindow.focus')", "toString('window.focus')");
shouldBe("targetWindow.focus.name", "''");
// Overriden using window.__proto__.blur = function() { return "new blur;" }
shouldBeTrue("canGet('targetWindow.blur')");
shouldBe("toString('targetWindow.blur')", "toString('window.blur')");
shouldBe("targetWindow.blur.name", "''");
// Overriden using window.history.close = "new close"
shouldBeTrue("canGet('targetWindow.close')");
shouldBe("toString('targetWindow.close')", "toString('window.close')");
shouldBe("targetWindow.close.name", "''");
if (window.testRunner)
testRunner.notifyDone();
......
......@@ -3,5 +3,5 @@
PASS: canGet('targetWindow.location.assign') should be 'false' and is.
PASS: canGet('targetWindow.location.reload') should be 'false' and is.
PASS: canGet('targetWindow.location.replace') should be 'true' and is.
PASS: toString('targetWindow.location.replace') should be 'function () { [native code] }' and is.
PASS: targetWindow.location.replace.name should be '' and is.
......@@ -24,7 +24,7 @@
// Overriden using window.location.replace = "new replace"
shouldBeTrue("canGet('targetWindow.location.replace')");
shouldBe("toString('targetWindow.location.replace')", "toString('window.location.replace')");
shouldBe("targetWindow.location.replace.name", "''");
if (window.testRunner)
testRunner.notifyDone();
......
......@@ -12,7 +12,7 @@ Frame: '<!--framePath //<!--frame0-->-->'
----- tests for putting window.history and its properties -----
PASS: window.location.assign should be 'function assign() { [native code] }' and is.
PASS: window.location.replace should be 'function () { [native code] }' and is.
PASS: window.location.replace should be 'function replace() { [native code] }' and is.
PASS: window.location.reload should be 'function reload() { [native code] }' and is.
PASS: window.location.toString should be 'function toString() { [native code] }' and is.
PASS: window.location.customAttribute should be 'customAttribute' and is.
......
......@@ -154,16 +154,16 @@ ALERT: PASS: window.top should be topOld and is.
ALERT: PASS: window.addEventListener should be 'function addEventListener() { [native code] }' and is.
ALERT: PASS: window.alert should be 'function alert() { [native code] }' and is.
ALERT: PASS: window.atob should be 'function atob() { [native code] }' and is.
ALERT: PASS: window.blur should be 'function () { [native code] }' and is.
ALERT: PASS: window.blur should be 'function blur() { [native code] }' and is.
ALERT: PASS: window.btoa should be 'function btoa() { [native code] }' and is.
ALERT: PASS: window.captureEvents should be 'function captureEvents() { [native code] }' and is.
ALERT: PASS: window.clearInterval should be 'function clearInterval() { [native code] }' and is.
ALERT: PASS: window.clearTimeout should be 'function clearTimeout() { [native code] }' and is.
ALERT: PASS: window.close should be 'function () { [native code] }' and is.
ALERT: PASS: window.close should be 'function close() { [native code] }' and is.
ALERT: PASS: window.confirm should be 'function confirm() { [native code] }' and is.
ALERT: PASS: window.eval should be 'function eval() { [native code] }' and is.
ALERT: PASS: window.find should be 'function find() { [native code] }' and is.
ALERT: PASS: window.focus should be 'function () { [native code] }' and is.
ALERT: PASS: window.focus should be 'function focus() { [native code] }' and is.
ALERT: PASS: window.getComputedStyle should be 'function getComputedStyle() { [native code] }' and is.
ALERT: PASS: window.getMatchedCSSRules should be 'undefined' and is.
ALERT: PASS: window.getSelection should be 'function getSelection() { [native code] }' and is.
......
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