Backed out 13 changesets (bug 987111) for disagreeing with some patch from b-i or fx-team in tonight's merge to hopefully fix a CLOSED TREE

Backed out changeset d4e390ceac27 (bug 987111)
Backed out changeset 5f88b5ef9496 (bug 987111)
Backed out changeset cdfd24ddf448 (bug 987111)
Backed out changeset 7883150e5471 (bug 987111)
Backed out changeset 407c7ca82ada (bug 987111)
Backed out changeset e7140ccf7e09 (bug 987111)
Backed out changeset 0a4d18d6306f (bug 987111)
Backed out changeset e7b7548867d9 (bug 987111)
Backed out changeset 944d128f135a (bug 987111)
Backed out changeset 33860f30fc4f (bug 987111)
Backed out changeset 518a915fb81b (bug 987111)
Backed out changeset 7576a51cf72e (bug 987111)
Backed out changeset 1a8dc1af9de6 (bug 987111)
This commit is contained in:
Wes Kocher 2014-06-04 22:12:50 -07:00
parent f64f892d7c
commit 915f3c652a
6 changed files with 30 additions and 431 deletions

View File

@ -102,7 +102,6 @@ nsDOMIdentity.prototype = {
*/
watch: function nsDOMIdentity_watch(aOptions = {}) {
aOptions = Cu.waiveXrays(aOptions);
if (this._rpWatcher) {
// For the initial release of Firefox Accounts, we support callers who
// invoke watch() either for Firefox Accounts, or Persona, but not both.
@ -154,7 +153,6 @@ nsDOMIdentity.prototype = {
},
request: function nsDOMIdentity_request(aOptions = {}) {
aOptions = Cu.waiveXrays(aOptions);
this._log("request: " + JSON.stringify(aOptions));
// Has the caller called watch() before this?

View File

@ -2895,7 +2895,6 @@ class PropertyDescriptorOperations
bool hasGetterObject() const { return desc()->attrs & JSPROP_GETTER; }
bool hasSetterObject() const { return desc()->attrs & JSPROP_SETTER; }
bool hasGetterOrSetterObject() const { return desc()->attrs & (JSPROP_GETTER | JSPROP_SETTER); }
bool hasGetterOrSetter() const { return desc()->getter || desc()->setter; }
bool isShared() const { return desc()->attrs & JSPROP_SHARED; }
bool isIndex() const { return desc()->attrs & JSPROP_INDEX; }
bool hasAttributes(unsigned attrs) const { return desc()->attrs & attrs; }
@ -2936,14 +2935,6 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
value().setUndefined();
}
void assign(JSPropertyDescriptor &other) {
object().set(other.obj);
setAttributes(other.attrs);
setGetter(other.getter);
setSetter(other.setter);
value().set(other.value);
}
JS::MutableHandleObject object() {
return JS::MutableHandleObject::fromMarkedLocation(&desc()->obj);
}

View File

@ -2587,7 +2587,6 @@ Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id
// that we're going to shadow. Make a property descriptor and define it.
Rooted<PropertyDescriptor> newDesc(cx);
newDesc.value().set(vp);
newDesc.setAttributes(JSPROP_ENUMERATE);
return handler->defineProperty(cx, receiver, id, &newDesc);
}

View File

@ -23,16 +23,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
const Cu = Components.utils;
let global = Cu.getGlobalForObject.bind(Cu);
function checkThrows(f, rgxp, msg) {
try {
f();
ok(false, "Should have thrown: " + msg);
} catch (e) {
ok(true, "Threw as expected: " + msg);
ok(rgxp.test(e), "Message correct: " + e);
}
}
simpleConstructors = ['Object', 'Function', 'Array', 'Boolean', 'Date', 'Number',
'String', 'RegExp', 'Error', 'InternalError', 'EvalError',
'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError',
@ -113,8 +103,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
testDate();
testObject();
// We could also test DataView and Iterator here for completeness, but it's
// more trouble than it's worth.
@ -122,30 +110,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
SimpleTest.finish();
}
// Maintain a static list of the properties that are available on each standard
// prototype, so that we make sure to audit any new ones to make sure they're
// Xray-safe.
//
// DO NOT CHANGE WTIHOUT REVIEW FROM AN XPCONNECT PEER.
var gPrototypeProperties = {};
gPrototypeProperties['Date'] =
["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear",
"getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay",
"getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds",
"getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", "setTime",
"setYear", "setFullYear", "setUTCFullYear", "setMonth", "setUTCMonth",
"setDate", "setUTCDate", "setHours", "setUTCHours", "setMinutes",
"setUTCMinutes", "setSeconds", "setUTCSeconds", "setMilliseconds",
"setUTCMilliseconds", "toUTCString", "toLocaleFormat", "toLocaleString",
"toLocaleDateString", "toLocaleTimeString", "toDateString", "toTimeString",
"toISOString", "toJSON", "toSource", "toString", "valueOf", "constructor",
"toGMTString"];
gPrototypeProperties['Object'] = /* __proto__ is intentionally excluded here, because
the JS engine filters it out of getOwnPropertyNames */
["constructor", "toSource", "toString", "toLocaleString", "valueOf", "watch",
"unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
"__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__"];
function filterOut(array, props) {
return array.filter(p => props.indexOf(p) == -1);
}
@ -154,19 +118,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
propsToSkip = propsToSkip || [];
let xrayProto = Object.getPrototypeOf(xray);
let localProto = window[classname].prototype;
is(Object.getOwnPropertyNames(localProto).sort().toSource(),
gPrototypeProperties[classname].sort().toSource(),
"A new property on the " + classname +
" prototype has been added! You need a security audit from an XPConnect peer");
let protoProps = filterOut(Object.getOwnPropertyNames(localProto), propsToSkip).sort();
let protoMethods = protoProps.filter(name => typeof localProto[name] == 'function' &&
name != 'constructor');
ok(protoMethods.length > 0, "Need something to test");
is(xrayProto, iwin[classname].prototype, "Xray proto is correct");
is(xrayProto, xray.__proto__, "Proto accessors agree");
var protoProto = classname == "Object" ? null : iwin.Object.prototype;
is(Object.getPrototypeOf(xrayProto), protoProto, "proto proto is correct");
is(Object.getPrototypeOf(xrayProto), iwin.Object.prototype, "proto proto is correct");
for (let name of protoMethods) {
info("Running tests for property: " + name);
ok(xrayProto.hasOwnProperty(name), "proto should have the property as own");
@ -211,91 +169,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
is(d.toLocaleString('de-DE'), d.wrappedJSObject.toLocaleString('de-DE'), "Results match");
}
function testObject() {
testXray('Object', iwin.Object.create(new iwin.Object()), new iwin.Object(), []);
// Construct an object full of tricky things.
var trickyObject =
iwin.eval('new Object({ \
primitiveProp: 42, objectProp: { foo: 2 }, \
xoProp: top.location, hasOwnProperty: 10, \
get getterProp() { return 2; }, \
set setterProp(x) { }, \
get getterSetterProp() { return 3; }, \
set getterSetterProp(x) { }, \
callableProp: function() { }, \
nonXrayableProp: new WeakMap() })');
// Make sure it looks right under the hood.
is(trickyObject.wrappedJSObject.getterProp, 2, "Underlying object has getter");
is(Cu.unwaiveXrays(trickyObject.wrappedJSObject.xoProp), top.location, "Underlying object has xo property");
// Test getOwnPropertyNames.
is(Object.getOwnPropertyNames(trickyObject).sort().toSource(),
['objectProp', 'primitiveProp'].toSource(), "getOwnPropertyNames should be filtered correctly");
// Test iteration and in-place modification. Beware of 'expando', which is the property
// we placed on the xray proto.
var propCount = 0;
for (let prop in trickyObject) {
if (prop == 'primitiveProp')
trickyObject[prop] = trickyObject[prop] - 10;
if (prop != 'expando')
trickyObject[prop] = trickyObject[prop];
++propCount;
}
is(propCount, 3, "Should iterate the correct number of times");
// Test Object.keys.
is(Object.keys(trickyObject).sort().toSource(),
['objectProp', 'primitiveProp'].toSource(), "Object.keys should be filtered correctly");
// Test getOwnPropertyDescriptor.
is(trickyObject.primitiveProp, 32, "primitive prop works");
is(trickyObject.objectProp.foo, 2, "object prop works");
is(typeof trickyObject.callableProp, 'undefined', "filtering works correctly");
is(Object.getOwnPropertyDescriptor(trickyObject, 'primitiveProp').value, 32, "getOwnPropertyDescriptor works");
is(Object.getOwnPropertyDescriptor(trickyObject, 'xoProp'), undefined, "filtering works with getOwnPropertyDescriptor");
// Test defineProperty.
trickyObject.primitiveSetByXray = 'fourty two';
is(trickyObject.primitiveSetByXray, 'fourty two', "Can set primitive correctly over Xray (ready via Xray)");
is(trickyObject.wrappedJSObject.primitiveSetByXray, 'fourty two', "Can set primitive correctly over Xray (ready via Waiver)");
var newContentObject = iwin.eval('new Object({prop: 99, get getterProp() { return 2; }})');
trickyObject.objectSetByXray = newContentObject;
is(trickyObject.objectSetByXray.prop, 99, "Can set object correctly over Xray (ready via Xray)");
is(trickyObject.wrappedJSObject.objectSetByXray.prop, 99, "Can set object correctly over Xray (ready via Waiver)");
checkThrows(function() { trickyObject.rejectedProp = {foo: 33}}, /cross-origin object/,
"Should reject privileged object property definition");
// Test JSON.stringify.
var jsonStr = JSON.stringify(newContentObject);
ok(/prop/.test(jsonStr), "JSON stringification should work: " + jsonStr);
// Test deletion.
delete newContentObject.prop;
ok(!newContentObject.hasOwnProperty('prop'), "Deletion should work");
ok(!newContentObject.wrappedJSObject.hasOwnProperty('prop'), "Deletion should forward");
delete newContentObject.getterProp;
ok(newContentObject.wrappedJSObject.hasOwnProperty('getterProp'), "Deletion be no-op for filtered property");
// We should be able to overwrite an existing accessor prop and convert it
// to a value prop.
is(trickyObject.wrappedJSObject.getterSetterProp, 3, "Underlying object has getter");
is(trickyObject.getterSetterProp, undefined, "Filtering properly over Xray");
trickyObject.getterSetterProp = 'redefined';
is(trickyObject.getterSetterProp, 'redefined', "Redefinition works");
is(trickyObject.wrappedJSObject.getterSetterProp, 'redefined', "Redefinition forwards");
checkThrows(function() { trickyObject.hasOwnProperty = 33; }, /shadow/,
"Should reject shadowing of pre-existing inherited properties over Xrays");
checkThrows(function() { Object.defineProperty(trickyObject, 'rejectedProp', { get: function() {}}); },
/accessor property/, "Should reject accessor property definition");
}
]]>
</script>
<iframe id="ifr" onload="go();" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html" />

View File

@ -120,21 +120,6 @@ WrapperFactory::DoubleWrap(JSContext *cx, HandleObject obj, unsigned flags)
return obj;
}
// In general, we're trying to deprecate COWs incrementally as we introduce
// Xrays to the corresponding object types. But switching off COWs for Object
// instances would be too tumultuous at present, so we punt on that for later.
static bool
ForceCOWBehavior(JSObject *obj)
{
if (IdentifyStandardInstanceOrPrototype(obj) == JSProto_Object) {
MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject,
"We should use XrayWrappers for standard ES Object instances "
"modulo this hack");
return true;
}
return false;
}
JSObject *
WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope,
HandleObject objArg, unsigned flags)
@ -184,7 +169,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope,
bool subsumes = AccessCheck::subsumes(js::GetContextCompartment(cx),
js::GetObjectCompartment(obj));
XrayType xrayType = GetXrayType(obj);
if (!subsumes && (xrayType == NotXray || ForceCOWBehavior(obj))) {
if (!subsumes && xrayType == NotXray) {
JSProtoKey key = JSProto_Null;
{
JSAutoCompartment ac(cx, obj);
@ -433,12 +418,7 @@ WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
// If this is a chrome object being exposed to content without Xrays, use
// a COW.
//
// We make an exception for Object instances, because we still rely on COWs
// for those in a lot of places in the tree.
else if (originIsChrome && !targetIsChrome &&
(xrayType == NotXray || ForceCOWBehavior(obj)))
{
else if (originIsChrome && !targetIsChrome && xrayType == NotXray) {
wrapper = &ChromeObjectWrapper::singleton;
}

View File

@ -18,7 +18,6 @@
#include "jsapi.h"
#include "jsprf.h"
#include "nsJSUtils.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/WindowBinding.h"
@ -44,7 +43,6 @@ IsJSXraySupported(JSProtoKey key)
{
switch (key) {
case JSProto_Date:
case JSProto_Object:
return true;
default:
return false;
@ -160,11 +158,6 @@ public:
HandleObject wrapper, HandleObject holder,
HandleId id, MutableHandle<JSPropertyDescriptor> desc);
bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) {
*bp = true;
return true;
}
virtual void preserveWrapper(JSObject *target) = 0;
static bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id,
@ -215,9 +208,9 @@ public:
virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc, bool *defined);
static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc, bool *defined);
virtual bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
AutoIdVector &props);
static bool call(JSContext *cx, HandleObject wrapper,
@ -266,9 +259,9 @@ public:
virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc, bool *defined);
static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc, bool *defined);
static bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
virtual bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
@ -311,11 +304,14 @@ public:
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp);
bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc, bool *defined);
static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc, bool *defined)
{
// There's no useful per-trait work to do here. Punt back up to the common code.
*defined = false;
return true;
}
virtual bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
AutoIdVector &props);
@ -350,15 +346,8 @@ public:
JS::MutableHandleObject protop)
{
RootedObject holder(cx, ensureHolder(cx, wrapper));
JSProtoKey key = getProtoKey(holder);
if (isPrototype(holder)) {
if (key == JSProto_Object) {
protop.set(nullptr);
return true;
}
key = JSProto_Object;
}
JSProtoKey key = isPrototype(holder) ? JSProto_Object
: getProtoKey(holder);
{
JSAutoCompartment ac(cx, target);
if (!JS_GetClassPrototype(cx, key, protop))
@ -390,12 +379,6 @@ public:
return js::GetReservedSlot(holder, SLOT_ISPROTOTYPE).toBoolean();
}
static bool getOwnPropertyFromTargetIfSafe(JSContext *cx,
HandleObject target,
HandleObject wrapper,
HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static const JSClass HolderClass;
static JSXrayTraits singleton;
};
@ -407,101 +390,6 @@ const JSClass JSXrayTraits::HolderClass = {
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
};
inline bool
SilentFailure(JSContext *cx, HandleId id, const char *reason)
{
#ifdef DEBUG
nsDependentJSString name(id);
AutoFilename filename;
unsigned line = 0;
DescribeScriptedCaller(cx, &filename, &line);
NS_WARNING(nsPrintfCString("Denied access to property |%s| on Xrayed Object: %s (@%s:%u)",
NS_LossyConvertUTF16toASCII(name).get(), reason,
filename.get(), line).get());
#endif
return true;
}
bool JSXrayTraits::getOwnPropertyFromTargetIfSafe(JSContext *cx,
HandleObject target,
HandleObject wrapper,
HandleId idArg,
MutableHandle<JSPropertyDescriptor> outDesc)
{
// Note - This function operates in the target compartment, because it
// avoids a bunch of back-and-forth wrapping in enumerateNames.
MOZ_ASSERT(getTargetObject(wrapper) == target);
MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx));
MOZ_ASSERT(WrapperFactory::IsXrayWrapper(wrapper));
MOZ_ASSERT(outDesc.object() == nullptr);
RootedId id(cx, idArg);
if (!JS_WrapId(cx, &id))
return false;
Rooted<JSPropertyDescriptor> desc(cx);
if (!JS_GetOwnPropertyDescriptorById(cx, target, id, &desc))
return false;
// If the property doesn't exist at all, we're done.
if (!desc.object())
return true;
// Disallow accessor properties.
if (desc.hasGetterOrSetter())
return SilentFailure(cx, id, "Property has accessor");
// Apply extra scrutiny to objects.
if (desc.value().isObject()) {
RootedObject propObj(cx, js::UncheckedUnwrap(&desc.value().toObject()));
JSAutoCompartment ac(cx, propObj);
// Disallow non-subsumed objects.
if (!AccessCheck::subsumes(target, propObj))
return SilentFailure(cx, id, "Value not same-origin with target");
// Disallow non-Xrayable objects.
if (GetXrayType(propObj) == NotXray) {
// Note - We're going add Xrays for Arrays/TypedArrays soon in
// bug 987163, so we don't want to cause unnecessary compat churn
// by making xrayedObj.arrayProp stop working temporarily, and then
// start working again. At the same time, this is an important check,
// and this patch wouldn't be as useful without it. So we just
// forcibly override the behavior here for Arrays until bug 987163
// lands.
JSProtoKey key = IdentifyStandardInstanceOrPrototype(propObj);
if (key != JSProto_Array && key != JSProto_Uint8ClampedArray &&
key != JSProto_Int8Array && key != JSProto_Uint8Array &&
key != JSProto_Int16Array && key != JSProto_Uint16Array &&
key != JSProto_Int32Array && key != JSProto_Uint32Array &&
key != JSProto_Float32Array && key != JSProto_Float64Array)
{
return SilentFailure(cx, id, "Value not Xrayable");
}
}
// Disallow callables.
if (JS_ObjectIsCallable(cx, propObj))
return SilentFailure(cx, id, "Value is callable");
}
// Disallow any property that shadows something on its (Xrayed)
// prototype chain.
JSAutoCompartment ac2(cx, wrapper);
RootedObject proto(cx);
bool foundOnProto = false;
if (!JS_GetPrototype(cx, wrapper, &proto) ||
(proto && !JS_HasPropertyById(cx, proto, id, &foundOnProto)))
{
return false;
}
if (foundOnProto)
return SilentFailure(cx, id, "Value shadows a property on the standard prototype");
// We made it! Assign over the descriptor, and don't forget to wrap.
outDesc.assign(desc.get());
return true;
}
bool
JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
HandleObject wrapper, HandleObject holder,
@ -514,27 +402,9 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
if (!ok || desc.object())
return ok;
RootedObject target(cx, getTargetObject(wrapper));
if (!isPrototype(holder)) {
// For object instances, we expose some properties from the underlying
// object, but only after filtering them carefully.
switch (getProtoKey(holder)) {
case JSProto_Object:
{
JSAutoCompartment ac(cx, target);
if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, desc))
return false;
}
return JS_WrapPropertyDescriptor(cx, desc);
default:
// Most instance (non-prototypes) Xrays don't have anything on them.
break;
}
// The rest of this function applies only to prototypes.
// Non-prototypes don't have anything on them yet.
if (!isPrototype(holder))
return true;
}
// The non-HasPrototypes semantics implemented by traditional Xrays are kind
// of broken with respect to |own|-ness and the holder. The common code
@ -549,6 +419,7 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
}
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
RootedObject target(cx, getTargetObject(wrapper));
const js::Class *clasp = js::GetObjectClass(target);
JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
MOZ_ASSERT(protoKey == getProtoKey(holder));
@ -658,127 +529,20 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
return true;
}
bool
JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp)
{
RootedObject holder(cx, ensureHolder(cx, wrapper));
// If we're using Object Xrays, we allow callers to attempt to delete any
// property from the underlying object that they are able to resolve. Note
// that this deleting may fail if the property is non-configurable.
bool isObjectInstance = getProtoKey(holder) == JSProto_Object && !isPrototype(holder);
if (isObjectInstance) {
RootedObject target(cx, getTargetObject(wrapper));
JSAutoCompartment ac(cx, target);
Rooted<JSPropertyDescriptor> desc(cx);
if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, &desc))
return false;
if (desc.object())
return JS_DeletePropertyById2(cx, target, id, bp);
}
*bp = true;
return true;
}
bool
JSXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc,
Handle<JSPropertyDescriptor> existingDesc,
bool *defined)
{
*defined = false;
RootedObject holder(cx, ensureHolder(cx, wrapper));
if (!holder)
return false;
// Object instances are special. For that case, we forward property
// definitions to the underlying object if the following conditions are met:
// * The property being defined is a value-prop.
// * The property being defined is either a primitive or subsumed by the target.
// * As seen from the Xray, any existing property that we would overwrite is an
// |own| value-prop.
//
// To avoid confusion, we disallow expandos on Object instances, and
// therefore raise an exception here if the above conditions aren't met.
bool isObjectInstance = getProtoKey(holder) == JSProto_Object && !isPrototype(holder);
if (isObjectInstance) {
RootedObject target(cx, getTargetObject(wrapper));
if (desc.hasGetterOrSetter()) {
JS_ReportError(cx, "Not allowed to define accessor property on [Object] XrayWrapper");
return false;
}
if (desc.value().isObject() &&
!AccessCheck::subsumes(target, js::UncheckedUnwrap(&desc.value().toObject())))
{
JS_ReportError(cx, "Not allowed to define cross-origin object as property on [Object] XrayWrapper");
return false;
}
if (existingDesc.hasGetterOrSetter()) {
JS_ReportError(cx, "Not allowed to overwrite accessor property on [Object] XrayWrapper");
return false;
}
if (existingDesc.object() && existingDesc.object() != wrapper) {
JS_ReportError(cx, "Not allowed to shadow non-own Xray-resolved property on [Object] XrayWrapper");
return false;
}
JSAutoCompartment ac(cx, target);
if (!JS_WrapPropertyDescriptor(cx, desc) ||
!JS_DefinePropertyById(cx, target, id, desc.value(), desc.attributes(),
JS_PropertyStub, JS_StrictPropertyStub))
{
return false;
}
*defined = true;
return true;
}
return true;
}
bool
JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
AutoIdVector &props)
{
RootedObject target(cx, getTargetObject(wrapper));
RootedObject holder(cx, ensureHolder(cx, wrapper));
if (!holder)
return false;
if (!isPrototype(holder)) {
// For object instances, we expose some properties from the underlying
// object, but only after filtering them carefully.
switch (getProtoKey(holder)) {
case JSProto_Object:
MOZ_ASSERT(props.empty());
{
JSAutoCompartment ac(cx, target);
AutoIdVector targetProps(cx);
if (!js::GetPropertyNames(cx, target, flags | JSITER_OWNONLY, &targetProps))
return false;
// Loop over the properties, and only pass along the ones that
// we determine to be safe.
for (size_t i = 0; i < targetProps.length(); ++i) {
Rooted<JSPropertyDescriptor> desc(cx);
RootedId id(cx, targetProps[i]);
if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, &desc))
return false;
if (desc.object())
props.append(id);
}
}
return JS_WrapAutoIdVector(cx, props);
default:
// Most instance (non-prototypes) Xrays don't have anything on them.
break;
}
// The rest of this function applies only to prototypes.
// Non-prototypes don't have anything on them yet.
if (!isPrototype(holder))
return true;
}
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
RootedObject target(cx, getTargetObject(wrapper));
const js::Class *clasp = js::GetObjectClass(target);
MOZ_ASSERT(JSCLASS_CACHED_PROTO_KEY(clasp) == getProtoKey(holder));
MOZ_ASSERT(clasp->spec.defined());
@ -2278,20 +2042,14 @@ XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, HandleObject wrapper,
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET);
Rooted<JSPropertyDescriptor> existing_desc(cx);
if (!JS_GetPropertyDescriptorById(cx, wrapper, id, &existing_desc))
if (!getOwnPropertyDescriptor(cx, wrapper, id, &existing_desc))
return false;
// Note that the check here is intended to differentiate between own and
// non-own properties, since the above lookup is not limited to own
// properties. At present, this may not always do the right thing because
// we often lie (sloppily) about where we found properties and set
// desc.object() to |wrapper|. Once we fully fix our Xray prototype semantics,
// this should work as intended.
if (existing_desc.object() == wrapper && existing_desc.isPermanent())
if (existing_desc.object() && existing_desc.isPermanent())
return true; // silently ignore attempt to overwrite native property
bool defined = false;
if (!Traits::singleton.defineProperty(cx, wrapper, id, desc, existing_desc, &defined))
if (!Traits::defineProperty(cx, wrapper, id, desc, existing_desc, &defined))
return false;
if (defined)
return true;
@ -2344,8 +2102,8 @@ XrayWrapper<Base, Traits>::delete_(JSContext *cx, HandleObject wrapper,
JSAutoCompartment ac(cx, expando);
return JS_DeletePropertyById2(cx, expando, id, bp);
}
return Traits::singleton.delete_(cx, wrapper, id, bp);
*bp = true;
return true;
}
template <typename Base, typename Traits>