Bug 787070 - Expandos on the xray of DOM prototypes should have effect on xrays of DOM nodes, make Xrays walk the prototype chain when resolving DOM properties. r=bholley.

* * *
Bug 787070 - Expandos on the xray of DOM prototypes should have effect on xrays of DOM nodes, remove obsolete code. r=bholley.

--HG--
extra : rebase_source : 7a9aa81d3e9d74ed958374942020474147aa4f86
This commit is contained in:
Peter Van der Beken 2014-09-15 16:51:40 +02:00
parent 02658d3525
commit d1b9102a2f
8 changed files with 153 additions and 379 deletions

View File

@ -250,7 +250,7 @@ const NativePropertyHooks sWindowNamedPropertiesNativePropertyHooks[] = { {
static const DOMIfaceAndProtoJSClass WindowNamedPropertiesClass = {
PROXY_CLASS_DEF("WindowProperties",
DOM_INTERFACE_PROTO_SLOTS_BASE, /* extra slots */
0),
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS),
eNamedPropertiesObject,
sWindowNamedPropertiesNativePropertyHooks,
"[object WindowProperties]",

View File

@ -36,6 +36,7 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/DOMErrorBinding.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/HTMLObjectElement.h"
#include "mozilla/dom/HTMLObjectElementBinding.h"
#include "mozilla/dom/HTMLSharedObjectElement.h"
@ -912,14 +913,14 @@ ThrowConstructorWithoutNew(JSContext* cx, const char* name)
inline const NativePropertyHooks*
GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
DOMObjectType& type, bool& isGlobal)
DOMObjectType& type)
{
const js::Class* clasp = js::GetObjectClass(obj);
isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
const DOMJSClass* domClass = GetDOMClass(clasp);
if (domClass) {
type = eInstance;
bool isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
type = isGlobal ? eGlobalInstance : eInstance;
return domClass->mNativeHooks;
}
@ -941,14 +942,6 @@ GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
return ifaceAndProtoJSClass->mNativeHooks;
}
static bool
XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
const NativePropertyHooks* nativePropertyHooks,
DOMObjectType type, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc,
bool& cacheOnHolder);
static bool
XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
@ -1054,7 +1047,7 @@ XrayResolveMethod(JSContext* cx, JS::Handle<JSObject*> wrapper,
// Try to resolve a property as an unforgeable property from the given
// NativeProperties, if it's there. nativeProperties is allowed to be null (in
// which case we of course won't resolve anything).
/* static */ bool
static bool
XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc,
@ -1220,7 +1213,7 @@ DEBUG_CheckXBLCallable(JSContext *cx, JSObject *obj)
MOZ_ASSERT(JS::IsCallable(obj));
}
void
static void
DEBUG_CheckXBLLookup(JSContext *cx, JSPropertyDescriptor *desc)
{
if (!desc->obj)
@ -1242,7 +1235,7 @@ DEBUG_CheckXBLLookup(JSContext *cx, JSPropertyDescriptor *desc)
#define DEBUG_CheckXBLLookup(a, b) {}
#endif
bool
/* static */ bool
XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc,
@ -1251,9 +1244,10 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
cacheOnHolder = false;
DOMObjectType type;
bool isGlobal;
const NativePropertyHooks *nativePropertyHooks =
GetNativePropertyHooks(cx, obj, type, isGlobal);
GetNativePropertyHooks(cx, obj, type);
const NativePropertiesHolder& nativeProperties =
nativePropertyHooks->mNativeProperties;
ResolveOwnProperty resolveOwnProperty =
nativePropertyHooks->mResolveOwnProperty;
@ -1263,7 +1257,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
}
// Check for unforgeable properties first.
if (type == eInstance) {
if (IsInstance(type)) {
const NativePropertiesHolder& nativeProperties =
nativePropertyHooks->mNativeProperties;
if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
@ -1271,11 +1265,8 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
return false;
}
if (desc.object()) {
return true;
}
if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
if (!desc.object() && xpc::AccessCheck::isChrome(wrapper) &&
!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
nativeProperties.chromeOnly)) {
return false;
}
@ -1285,21 +1276,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
}
}
if (type != eInstance || (isGlobal && GlobalPropertiesAreOwn())) {
// For prototype objects and interface objects, just return their
// normal set of properties. For global objects the WebIDL properties live
// on the instance objects, so resolve those here too.
if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
obj, id, desc, cacheOnHolder)) {
return false;
}
if (desc.object()) {
return true;
}
}
if (type == eInstance) {
if (IsInstance(type)) {
if (resolveOwnProperty) {
if (!resolveOwnProperty(cx, wrapper, obj, id, desc)) {
return false;
@ -1307,27 +1284,46 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
if (desc.object()) {
// None of these should be cached on the holder, since they're dynamic.
cacheOnHolder = false;
return true;
}
}
// If we're a special scope for in-content XBL, our script expects to see
// the bound XBL methods and attributes when accessing content. However,
// these members are implemented in content via custom-spliced prototypes,
// and thus aren't visible through Xray wrappers unless we handle them
// explicitly. So we check if we're running in such a scope, and if so,
// whether the wrappee is a bound element. If it is, we do a lookup via
// specialized XBL machinery.
//
// While we have to do some sketchy walking through content land, we should
// be protected by read-only/non-configurable properties, and any functions
// we end up with should _always_ be living in our own scope (the XBL scope).
// Make sure to assert that.
Element* element;
if (xpc::ObjectScope(wrapper)->IsContentXBLScope() &&
NS_SUCCEEDED(UNWRAP_OBJECT(Element, obj, element))) {
if (!nsContentUtils::LookupBindingMember(cx, element, id, desc)) {
return false;
}
DEBUG_CheckXBLLookup(cx, desc.address());
if (desc.object()) {
// XBL properties shouldn't be cached on the holder, as they might be
// shadowed by own properties returned from mResolveOwnProperty.
desc.object().set(wrapper);
return true;
}
}
}
return true;
}
/* static */ bool
XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
const NativePropertyHooks* nativePropertyHooks,
DOMObjectType type, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc,
bool& cacheOnHolder)
{
MOZ_ASSERT(type != eNamedPropertiesObject);
if (type == eInterface) {
// For non-global instance Xrays there are no other properties, so return
// here for them.
if (type != eGlobalInstance || !GlobalPropertiesAreOwn()) {
return true;
}
} else if (type == eInterface) {
if (IdEquals(id, "prototype")) {
return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
ResolvePrototypeOrConstructor(cx, wrapper, obj,
@ -1351,17 +1347,22 @@ XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
return JS_WrapPropertyDescriptor(cx, desc);
}
}
} else {
MOZ_ASSERT(IsInterfacePrototype(type));
if (type == eInterfacePrototype && IdEquals(id, "constructor")) {
return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
ResolvePrototypeOrConstructor(cx, wrapper, obj,
nativePropertyHooks->mConstructorID,
0, desc, cacheOnHolder);
}
if (IdEquals(id, "constructor")) {
return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
ResolvePrototypeOrConstructor(cx, wrapper, obj,
nativePropertyHooks->mConstructorID,
0, desc, cacheOnHolder);
}
const NativePropertiesHolder& nativeProperties =
nativePropertyHooks->mNativeProperties;
// The properties for globals live on the instance, so return here as there
// are no properties on their interface prototype object.
if (type == eGlobalInterfacePrototype && GlobalPropertiesAreOwn()) {
return true;
}
}
if (nativeProperties.regular &&
!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
@ -1380,56 +1381,6 @@ XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
return true;
}
bool
XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc,
bool& cacheOnHolder)
{
cacheOnHolder = false;
DOMObjectType type;
bool isGlobal;
const NativePropertyHooks* nativePropertyHooks =
GetNativePropertyHooks(cx, obj, type, isGlobal);
if (type == eNamedPropertiesObject) {
return true;
}
if (type == eInstance) {
// Global objects return their interfaces' properties from
// XrayResolveOwnProperty, so skip those.
if (isGlobal && GlobalPropertiesAreOwn()) {
nativePropertyHooks = nativePropertyHooks->mProtoHooks;
}
// Force the type to be eInterfacePrototype, since we need to walk the
// prototype chain.
type = eInterfacePrototype;
}
if (type == eInterfacePrototype) {
while (nativePropertyHooks) {
if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
obj, id, desc, cacheOnHolder)) {
return false;
}
if (desc.object()) {
return true;
}
nativePropertyHooks = nativePropertyHooks->mProtoHooks;
}
return true;
}
return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj,
id, desc, cacheOnHolder);
}
bool
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
@ -1483,19 +1434,23 @@ bool
XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
unsigned flags, JS::AutoIdVector& props,
DOMObjectType type, bool isGlobal,
DOMObjectType type,
const NativeProperties* nativeProperties)
{
MOZ_ASSERT(type != eNamedPropertiesObject);
if (type == eInstance) {
if (IsInstance(type)) {
ENUMERATE_IF_DEFINED(unforgeableMethod);
ENUMERATE_IF_DEFINED(unforgeableAttribute);
if (type == eGlobalInstance && GlobalPropertiesAreOwn()) {
ENUMERATE_IF_DEFINED(method);
ENUMERATE_IF_DEFINED(attribute);
}
} else if (type == eInterface) {
ENUMERATE_IF_DEFINED(staticMethod);
ENUMERATE_IF_DEFINED(staticAttribute);
} else {
MOZ_ASSERT(type == eInterfacePrototype);
} else if (type != eGlobalInterfacePrototype || !GlobalPropertiesAreOwn()) {
MOZ_ASSERT(IsInterfacePrototype(type));
ENUMERATE_IF_DEFINED(method);
ENUMERATE_IF_DEFINED(attribute);
}
@ -1524,7 +1479,7 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
bool
XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
const NativePropertyHooks* nativePropertyHooks,
DOMObjectType type, bool isGlobal,
DOMObjectType type,
JS::Handle<JSObject*> obj, unsigned flags,
JS::AutoIdVector& props)
{
@ -1536,7 +1491,7 @@ XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
return false;
}
if (type == eInterfacePrototype &&
if (IsInterfacePrototype(type) &&
nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
(flags & JSITER_HIDDEN) &&
!AddStringToIDVector(cx, props, "constructor")) {
@ -1547,14 +1502,14 @@ XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
nativePropertyHooks->mNativeProperties;
if (nativeProperties.regular &&
!XrayEnumerateProperties(cx, wrapper, obj, flags, props, type, isGlobal,
!XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
nativeProperties.regular)) {
return false;
}
if (nativeProperties.chromeOnly &&
xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
!XrayEnumerateProperties(cx, wrapper, obj, flags, props, type, isGlobal,
!XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
nativeProperties.chromeOnly)) {
return false;
}
@ -1568,9 +1523,8 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
unsigned flags, JS::AutoIdVector& props)
{
DOMObjectType type;
bool isGlobal;
const NativePropertyHooks* nativePropertyHooks =
GetNativePropertyHooks(cx, obj, type, isGlobal);
GetNativePropertyHooks(cx, obj, type);
EnumerateOwnProperties enumerateOwnProperties =
nativePropertyHooks->mEnumerateOwnProperties;
@ -1578,46 +1532,18 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
return enumerateOwnProperties(cx, wrapper, obj, props);
}
if (type == eInstance) {
if (IsInstance(type)) {
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1071189
// Should do something about XBL properties too.
if (enumerateOwnProperties &&
!enumerateOwnProperties(cx, wrapper, obj, props)) {
return false;
}
// Handle Unforgeable properties.
if (!XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
isGlobal, obj, flags, props)) {
return false;
}
// This will incorrectly return properties from EventTarget.prototype as own
// property names for Window.
if (!(isGlobal && GlobalPropertiesAreOwn()) && (flags & JSITER_OWNONLY)) {
return true;
}
// Force the type to be eInterfacePrototype, since we need to walk the
// prototype chain.
type = eInterfacePrototype;
}
if (type == eInterfacePrototype) {
do {
if (!XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
isGlobal, obj, flags, props)) {
return false;
}
if (flags & JSITER_OWNONLY) {
return true;
}
} while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks));
return true;
}
return XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
isGlobal, obj, flags, props);
return (type == eGlobalInterfacePrototype && GlobalPropertiesAreOwn()) ||
XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type,
obj, flags, props);
}
NativePropertyHooks sWorkerNativePropertyHooks = {
@ -1740,85 +1666,6 @@ DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
return true;
}
static JSString*
ConcatJSString(JSContext* cx, const char* pre, JS::Handle<JSString*> str, const char* post)
{
if (!str) {
return nullptr;
}
JS::Rooted<JSString*> preString(cx, JS_NewStringCopyN(cx, pre, strlen(pre)));
JS::Rooted<JSString*> postString(cx, JS_NewStringCopyN(cx, post, strlen(post)));
if (!preString || !postString) {
return nullptr;
}
preString = JS_ConcatStrings(cx, preString, str);
if (!preString) {
return nullptr;
}
return JS_ConcatStrings(cx, preString, postString);
}
bool
NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
JS::MutableHandle<JS::Value> v)
{
JS::Rooted<JSPropertyDescriptor> toStringDesc(cx);
toStringDesc.object().set(nullptr);
toStringDesc.setAttributes(0);
toStringDesc.setGetter(nullptr);
toStringDesc.setSetter(nullptr);
toStringDesc.value().set(JS::UndefinedValue());
JS::Rooted<jsid> id(cx,
nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
bool unused;
if (!XrayResolveNativeProperty(cx, wrapper, obj, id, &toStringDesc, unused)) {
return false;
}
JS::Rooted<JSString*> str(cx);
{
JSAutoCompartment ac(cx, obj);
if (toStringDesc.object()) {
JS::Rooted<JS::Value> toString(cx, toStringDesc.value());
if (!JS_WrapValue(cx, &toString)) {
return false;
}
MOZ_ASSERT(JS::IsCallable(&toString.toObject()));
JS::Rooted<JS::Value> toStringResult(cx);
if (JS_CallFunctionValue(cx, obj, toString, JS::HandleValueArray::empty(),
&toStringResult)) {
str = toStringResult.toString();
} else {
str = nullptr;
}
} else {
const js::Class* clasp = js::GetObjectClass(obj);
if (IsDOMClass(clasp)) {
str = JS_NewStringCopyZ(cx, clasp->name);
str = ConcatJSString(cx, "[object ", str, "]");
} else if (IsDOMIfaceAndProtoClass(clasp)) {
const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
DOMIfaceAndProtoJSClass::FromJSClass(clasp);
str = JS_NewStringCopyZ(cx, ifaceAndProtoJSClass->mToString);
} else {
MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(obj));
str = JS_DecompileFunction(cx, fun, 0);
}
}
}
if (!str) {
return false;
}
v.setString(str);
return JS_WrapValue(cx, v);
}
// Dynamically ensure that two objects don't end up with the same reserved slot.
class MOZ_STACK_CLASS AutoCloneDOMObjectSlotGuard

View File

@ -2317,7 +2317,7 @@ AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
// Implementation of the bits that XrayWrapper needs
/**
* This resolves indexed or named properties of obj.
* This resolves operations, attributes and constants of the interfaces for obj.
*
* wrapper is the Xray JS object.
* obj is the target object of the Xray, a binding's instance object or a
@ -2330,19 +2330,6 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::MutableHandle<JSPropertyDescriptor> desc,
bool& cacheOnHolder);
/**
* This resolves operations, attributes and constants of the interfaces for obj.
*
* wrapper is the Xray JS object.
* obj is the target object of the Xray, a binding's instance object or a
* interface or interface prototype object.
*/
bool
XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc,
bool& cacheOnHolder);
/**
* Define a property on obj through an Xray wrapper.
*
@ -2464,23 +2451,6 @@ MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
{
}
/**
* This creates a JSString containing the value that the toString function for
* obj should create according to the WebIDL specification, ignoring any
* modifications by script. The value is prefixed with pre and postfixed with
* post, unless this is called for an object that has a stringifier. It is
* specifically for use by Xray code.
*
* wrapper is the Xray JS object.
* obj is the target object of the Xray, a binding's instance object or a
* interface or interface prototype object.
* v contains the JSString for the value if the function returns true.
*/
bool
NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> obj,
JS::MutableHandle<JS::Value> v);
HAS_MEMBER(JSBindingFinalized)
template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
@ -2995,12 +2965,6 @@ GlobalPropertiesAreOwn()
void
AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
JS::Handle<JS::Value> aValue);
extern void
DEBUG_CheckXBLLookup(JSContext *cx, JSPropertyDescriptor *desc);
#else
#define DEBUG_CheckXBLLookup(a, b) {}
#endif
// Returns true if aObj's global has any of the permissions named in aPermissions

View File

@ -648,6 +648,7 @@ class CGPrototypeJSClass(CGThing):
if UseHolderForUnforgeable(self.descriptor):
slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */"
(protoGetter, _) = InterfacePrototypeObjectProtoGetter(self.descriptor)
type = "eGlobalInterfacePrototype" if self.descriptor.isGlobal() else "eInterfacePrototype"
return fill(
"""
static const DOMIfaceAndProtoJSClass PrototypeClass = {
@ -670,7 +671,7 @@ class CGPrototypeJSClass(CGThing):
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
},
eInterfacePrototype,
${type},
${hooks},
"[object ${name}Prototype]",
${prototypeID},
@ -680,6 +681,7 @@ class CGPrototypeJSClass(CGThing):
""",
name=self.descriptor.interface.identifier.name,
slotCount=slotCount,
type=type,
hooks=NativePropertyHooks(self.descriptor),
prototypeID=prototypeID,
depth=depth,

View File

@ -156,17 +156,34 @@ struct NativePropertyHooks
// constructors::id::_ID_Count.
constructors::ID mConstructorID;
// The NativePropertyHooks instance for the parent interface.
// The NativePropertyHooks instance for the parent interface (for
// ShimInterfaceInfo).
const NativePropertyHooks* mProtoHooks;
};
enum DOMObjectType {
eInstance,
eGlobalInstance,
eInterface,
eInterfacePrototype,
eGlobalInterfacePrototype,
eNamedPropertiesObject
};
inline
bool
IsInstance(DOMObjectType type)
{
return type == eInstance || type == eGlobalInstance;
}
inline
bool
IsInterfacePrototype(DOMObjectType type)
{
return type == eInterfacePrototype || type == eGlobalInterfacePrototype;
}
typedef JSObject* (*ParentGetter)(JSContext* aCx, JS::Handle<JSObject*> aObj);
typedef JSObject* (*ProtoGetter)(JSContext* aCx,
@ -229,7 +246,8 @@ struct DOMIfaceAndProtoJSClass
// initialization for aggregate/POD types.
const js::Class mBase;
// Either eInterface, eInterfacePrototype or eNamedPropertiesObject
// Either eInterface, eInterfacePrototype, eGlobalInterfacePrototype or
// eNamedPropertiesObject.
DOMObjectType mType;
const NativePropertyHooks* mNativeHooks;

View File

@ -74,12 +74,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
} finally {
isnot(xhr.prototype, "notok", "'XMLHttpRequest.prototype' should be readonly");
}
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
delete xhr.prototype;
} catch (e) {
ok(true, "'XMLHttpRequest.prototype' should be permanent");
}
var constructorWritable = false;
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox);
xhr.constructor = "ok";
@ -87,12 +82,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
} catch (e) {
ok(false, "'XMLHttpRequest.prototype.constructor' should be writeable");
}
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox);
delete xhr.constructor;
} catch (e) {
is(xhr.constructor, undefined, "'XMLHttpRequest.prototype.constructor' should be permanent");
}
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
is(xhr, XMLHttpRequest + "", "'XMLHttpRequest' in a sandbox should return the XMLHttpRequest interface object");
@ -114,6 +103,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
} catch (e) {
ok(false, "'new XMLHttpRequest()' shouldn't throw in a sandbox (1)");
}
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest.toString = function () { return 'Failed'; }; XMLHttpRequest;", sandbox);
is(xhr.toString(), XMLHttpRequest + "", "XMLHttpRequest.toString in the sandbox should not override the native toString behaviour");
} catch (e) {
ok(false, "'XMLHttpRequest' shouldn't throw in a sandbox");
}
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype.toString = function () { return 'Failed'; }; new XMLHttpRequest();", sandbox);
is(xhr.toString(), new XMLHttpRequest() + "", "XMLHttpRequest.prototype.toString in the sandbox should not override the native toString behaviour");
@ -137,6 +132,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
} catch (e) {
ok(false, "XMLHttpRequest.prototype manipulation via an Xray shouldn't throw" + e);
}
try {
Components.utils.evalInSandbox("XMLHttpRequest.prototype.a = 'expando a'", sandbox);
Components.utils.evalInSandbox("XMLHttpRequest.prototype.b = 'expando b'", sandbox);
Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox).b = 'xrayexpando';
var xhr = Components.utils.evalInSandbox("new XMLHttpRequest()", sandbox);
is(xhr.a, undefined, "'XMLHttpRequest()' in a sandbox should not have expandos from inside the sandbox");
is(xhr.b, "xrayexpando", "'new XMLHttpRequest()' in a sandbox should have Xray expandos");
} catch (e) {
ok(false, "'new XMLHttpRequest()' shouldn't throw in a sandbox");
}
try {
Components.utils.evalInSandbox("document.defaultView.XMLHttpRequest = function() {};", sandbox);
var win = Components.utils.evalInSandbox("document.defaultView", sandbox);

View File

@ -8,11 +8,10 @@
#include "AccessCheck.h"
#include "WrapperFactory.h"
#include "nsIContent.h"
#include "nsIControllers.h"
#include "nsDependentString.h"
#include "nsIScriptError.h"
#include "mozilla/dom/Element.h"
#include "nsContentUtils.h"
#include "XPCWrapper.h"
#include "xpcprivate.h"
@ -1053,9 +1052,6 @@ IsWindow(JSContext *cx, JSObject *wrapper)
return !!AsWindow(cx, wrapper);
}
static nsQueryInterface
do_QueryInterfaceNative(JSContext* cx, HandleObject wrapper);
void
XPCWrappedNativeXrayTraits::preserveWrapper(JSObject *target)
{
@ -1509,33 +1505,6 @@ DOMXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, Handl
JS_GetPropertyDescriptorById(cx, holder, id, desc);
}
bool
DOMXrayTraits::resolveNativeProperty(JSContext *cx, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc)
{
bool unused;
RootedObject obj(cx, getTargetObject(wrapper));
if (!XrayResolveNativeProperty(cx, wrapper, obj, id, desc, unused))
return false;
if (!desc.object() &&
id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING))
{
JSFunction *toString = JS_NewFunction(cx, XrayToString, 0, 0, wrapper, "toString");
if (!toString)
return false;
FillPropertyDescriptor(desc, wrapper, 0,
ObjectValue(*JS_GetFunctionObject(toString)));
}
MOZ_ASSERT(!desc.object() || desc.object() == wrapper, "What did we resolve this on?");
return true;
}
bool
DOMXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
@ -1636,6 +1605,14 @@ DOMXrayTraits::construct(JSContext *cx, HandleObject wrapper,
return true;
}
bool
DOMXrayTraits::getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject target,
JS::MutableHandleObject protop)
{
return mozilla::dom::XrayGetNativeProto(cx, target, protop);
}
void
DOMXrayTraits::preserveWrapper(JSObject *target)
{
@ -1729,19 +1706,7 @@ XrayToString(JSContext *cx, unsigned argc, Value *vp)
}
RootedObject obj(cx, XrayTraits::getTargetObject(wrapper));
XrayType type = GetXrayType(obj);
if (type == XrayForDOMObject) {
{
JSAutoCompartment ac(cx, obj);
JSString *str = JS_BasicObjectToString(cx, obj);
if (!str)
return false;
args.rval().setString(str);
}
return JS_WrapValue(cx, args.rval());
}
if (type != XrayForWrappedNative) {
if (GetXrayType(obj) != XrayForWrappedNative) {
JS_ReportError(cx, "XrayToString called on an incompatible object");
return false;
}
@ -1868,29 +1833,6 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, HandleObject wra
}
}
// If we're a special scope for in-content XBL, our script expects to see
// the bound XBL methods and attributes when accessing content. However,
// these members are implemented in content via custom-spliced prototypes,
// and thus aren't visible through Xray wrappers unless we handle them
// explicitly. So we check if we're running in such a scope, and if so,
// whether the wrappee is a bound element. If it is, we do a lookup via
// specialized XBL machinery.
//
// While we have to do some sketchy walking through content land, we should
// be protected by read-only/non-configurable properties, and any functions
// we end up with should _always_ be living in an XBL scope (usually ours,
// but could be another if the node has been adopted).
//
// Make sure to assert this.
nsCOMPtr<nsIContent> content;
if (!desc.object() && ObjectScope(wrapper)->IsContentXBLScope() &&
(content = do_QueryInterfaceNative(cx, wrapper)))
{
if (!nsContentUtils::LookupBindingMember(cx, content, id, desc))
return false;
DEBUG_CheckXBLLookup(cx, desc.address());
}
// If we still have nothing, we're done.
if (!desc.object())
return true;
@ -2119,6 +2061,7 @@ XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const
{
MOZ_ASSERT(!Traits::HasPrototype);
// Delegate to Traits.
// NB: None of the functions we call are prepared for the receiver not
// being the wrapper, so ignore the receiver here.
@ -2290,25 +2233,4 @@ template<>
const SCSecurityXrayXPCWN SCSecurityXrayXPCWN::singleton(0);
template class SCSecurityXrayXPCWN;
static nsQueryInterface
do_QueryInterfaceNative(JSContext* cx, HandleObject wrapper)
{
nsISupports* nativeSupports = nullptr;
if (IsWrapper(wrapper) && WrapperFactory::IsXrayWrapper(wrapper)) {
RootedObject target(cx, XrayTraits::getTargetObject(wrapper));
XrayType type = GetXrayType(target);
if (type == XrayForDOMObject) {
nativeSupports = UnwrapDOMObjectToISupports(target);
} else if (type == XrayForWrappedNative) {
XPCWrappedNative *wn = XPCWrappedNative::Get(target);
nativeSupports = wn->Native();
}
} else {
nsIXPConnect *xpc = nsXPConnect::XPConnect();
nativeSupports = xpc->GetNativeOfWrapper(cx, wrapper);
}
return nsQueryInterface(nativeSupports);
}
}

View File

@ -154,14 +154,26 @@ class DOMXrayTraits : public XrayTraits
{
public:
enum {
HasPrototype = 0
HasPrototype = 1
};
static const XrayType Type = XrayForDOMObject;
virtual bool resolveNativeProperty(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject holder, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
{
// Xrays for DOM binding objects have a prototype chain that consists of
// Xrays for the prototypes of the DOM binding object (ignoring changes
// in the prototype chain made by script, plugins or XBL). All properties for
// these Xrays are really own properties, either of the instance object or
// of the prototypes.
// FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1072482
// This should really be:
// MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
// but we can't do that yet because XrayUtils::HasNativeProperty calls this.
return true;
}
virtual bool resolveOwnProperty(JSContext *cx, const js::Wrapper &jsWrapper, JS::HandleObject wrapper,
JS::HandleObject holder, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
@ -177,6 +189,10 @@ public:
static bool construct(JSContext *cx, JS::HandleObject wrapper,
const JS::CallArgs &args, const js::Wrapper& baseInstance);
static bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject target,
JS::MutableHandleObject protop);
virtual void preserveWrapper(JSObject *target) MOZ_OVERRIDE;
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;