Bug 836301 - Hoist some assertions, remove a bunch of no-op trap overrides, and add assertions that we've entered our policy. r=mrbkap

This commit is contained in:
Bobby Holley 2013-02-25 13:54:18 -08:00
parent 59d3c6c36d
commit 0c9994db1d
12 changed files with 152 additions and 173 deletions

View File

@ -2157,8 +2157,9 @@ ia64*-hpux*)
# that behavior) that it's better to turn it off. # that behavior) that it's better to turn it off.
# MSVC warning C4819 warns some UTF-8 characters (e.g. copyright sign) # MSVC warning C4819 warns some UTF-8 characters (e.g. copyright sign)
# on non-Western system locales even if it is in a comment. # on non-Western system locales even if it is in a comment.
# khuey says we can safely ignore MSVC warning C4251
CFLAGS="$CFLAGS -wd4819" CFLAGS="$CFLAGS -wd4819"
CXXFLAGS="$CXXFLAGS -wd4345 -wd4351 -wd4482 -wd4800 -wd4819" CXXFLAGS="$CXXFLAGS -wd4251 -wd4345 -wd4351 -wd4482 -wd4800 -wd4819"
# make 'foo == bar;' error out # make 'foo == bar;' error out
CFLAGS="$CFLAGS -we4553" CFLAGS="$CFLAGS -we4553"
CXXFLAGS="$CXXFLAGS -we4553" CXXFLAGS="$CXXFLAGS -we4553"

View File

@ -1684,7 +1684,8 @@ ia64*-hpux*)
CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
# MSVC warning C4244 is ubiquitous, useless, and annoying. # MSVC warning C4244 is ubiquitous, useless, and annoying.
CXXFLAGS="$CXXFLAGS -wd4244" # khuey says we can safely ignore MSVC warning C4251
CXXFLAGS="$CXXFLAGS -wd4244 -wd4251"
# make 'foo == bar;' error out # make 'foo == bar;' error out
CFLAGS="$CFLAGS -we4553" CFLAGS="$CFLAGS -we4553"
CXXFLAGS="$CXXFLAGS -we4553" CXXFLAGS="$CXXFLAGS -we4553"

View File

@ -881,6 +881,9 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
ionReturnOverride_(MagicValue(JS_ARG_POISON)), ionReturnOverride_(MagicValue(JS_ARG_POISON)),
useHelperThreads_(useHelperThreads), useHelperThreads_(useHelperThreads),
requestedHelperThreadCount(-1), requestedHelperThreadCount(-1),
#ifdef DEBUG
enteredPolicy(NULL),
#endif
rngNonce(0) rngNonce(0)
{ {
/* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */

View File

@ -569,7 +569,7 @@ struct MallocProvider
namespace gc { namespace gc {
class MarkingValidator; class MarkingValidator;
} // namespace gc } // namespace gc
class AutoEnterPolicy;
} // namespace js } // namespace js
struct JSRuntime : js::RuntimeFriendFields, struct JSRuntime : js::RuntimeFriendFields,
@ -1301,7 +1301,11 @@ struct JSRuntime : js::RuntimeFriendFields,
return 0; return 0;
#endif #endif
} }
#ifdef DEBUG
public:
js::AutoEnterPolicy *enteredPolicy;
#endif
private: private:
/* /*
* Used to ensure that compartments created at the same time get different * Used to ensure that compartments created at the same time get different

View File

@ -1416,6 +1416,13 @@ class JS_FRIEND_API(AutoCTypesActivityCallback) {
} }
}; };
#ifdef DEBUG
extern JS_FRIEND_API(void)
assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id);
#else
inline JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id) {};
#endif
} /* namespace js */ } /* namespace js */
#endif /* jsfriendapi_h___ */ #endif /* jsfriendapi_h___ */

View File

@ -63,6 +63,38 @@ js::AutoEnterPolicy::reportError(JSContext *cx, jsid id)
} }
} }
#ifdef DEBUG
void
js::AutoEnterPolicy::recordEnter(JSContext *cx, JSObject *proxy, jsid id)
{
if (allowed()) {
context = cx;
enteredProxy.construct(cx, proxy);
enteredId.construct(cx, id);
prev = cx->runtime->enteredPolicy;
cx->runtime->enteredPolicy = this;
}
}
void
js::AutoEnterPolicy::recordLeave()
{
if (!enteredProxy.empty()) {
JS_ASSERT(context->runtime->enteredPolicy == this);
context->runtime->enteredPolicy = prev;
}
}
JS_FRIEND_API(void)
js::assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id)
{
MOZ_ASSERT(proxy->isProxy());
MOZ_ASSERT(cx->runtime->enteredPolicy);
MOZ_ASSERT(cx->runtime->enteredPolicy->enteredProxy.ref().get() == proxy);
MOZ_ASSERT(cx->runtime->enteredPolicy->enteredId.ref().get() == id);
}
#endif
BaseProxyHandler::BaseProxyHandler(void *family) BaseProxyHandler::BaseProxyHandler(void *family)
: mFamily(family), : mFamily(family),
mHasPrototype(false), mHasPrototype(false),
@ -85,6 +117,7 @@ BaseProxyHandler::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act,
bool bool
BaseProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp) BaseProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
{ {
assertEnteredPolicy(cx, proxy_, id_);
RootedObject proxy(cx, proxy_); RootedObject proxy(cx, proxy_);
RootedId id(cx, id_); RootedId id(cx, id_);
AutoPropertyDescriptorRooter desc(cx); AutoPropertyDescriptorRooter desc(cx);
@ -97,6 +130,7 @@ BaseProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
bool bool
BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp) BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
{ {
assertEnteredPolicy(cx, proxy_, id_);
RootedObject proxy(cx, proxy_); RootedObject proxy(cx, proxy_);
RootedId id(cx, id_); RootedId id(cx, id_);
AutoPropertyDescriptorRooter desc(cx); AutoPropertyDescriptorRooter desc(cx);
@ -109,6 +143,7 @@ BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
bool bool
BaseProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_, jsid id_, Value *vp) BaseProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_, jsid id_, Value *vp)
{ {
assertEnteredPolicy(cx, proxy, id_);
RootedObject receiver(cx, receiver_); RootedObject receiver(cx, receiver_);
RootedId id(cx, id_); RootedId id(cx, id_);
@ -150,6 +185,7 @@ BaseProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject
RootedId id(cx); RootedId id(cx);
if (!IndexToId(cx, index, &id)) if (!IndexToId(cx, index, &id))
return false; return false;
assertEnteredPolicy(cx, proxy, id);
if (!has(cx, proxy, id, present)) if (!has(cx, proxy, id, present))
return false; return false;
@ -166,6 +202,7 @@ bool
BaseProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict, BaseProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict,
Value *vp) Value *vp)
{ {
assertEnteredPolicy(cx, proxy_, id_);
RootedObject proxy(cx, proxy_), receiver(cx, receiver_); RootedObject proxy(cx, proxy_), receiver(cx, receiver_);
RootedId id(cx, id_); RootedId id(cx, id_);
@ -242,6 +279,7 @@ BaseProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid
bool bool
BaseProxyHandler::keys(JSContext *cx, JSObject *proxyArg, AutoIdVector &props) BaseProxyHandler::keys(JSContext *cx, JSObject *proxyArg, AutoIdVector &props)
{ {
assertEnteredPolicy(cx, proxyArg, JSID_VOID);
JS_ASSERT(props.length() == 0); JS_ASSERT(props.length() == 0);
RootedObject proxy(cx, proxyArg); RootedObject proxy(cx, proxyArg);
@ -255,6 +293,7 @@ BaseProxyHandler::keys(JSContext *cx, JSObject *proxyArg, AutoIdVector &props)
for (size_t j = 0, len = props.length(); j < len; j++) { for (size_t j = 0, len = props.length(); j < len; j++) {
JS_ASSERT(i <= j); JS_ASSERT(i <= j);
jsid id = props[j]; jsid id = props[j];
AutoWaivePolicy policy(cx, proxy, id);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0)) if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
return false; return false;
if (desc.obj && (desc.attrs & JSPROP_ENUMERATE)) if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
@ -270,6 +309,7 @@ BaseProxyHandler::keys(JSContext *cx, JSObject *proxyArg, AutoIdVector &props)
bool bool
BaseProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp) BaseProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
{ {
assertEnteredPolicy(cx, proxy_, JSID_VOID);
RootedObject proxy(cx, proxy_); RootedObject proxy(cx, proxy_);
AutoIdVector props(cx); AutoIdVector props(cx);
@ -291,6 +331,7 @@ bool
BaseProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc, BaseProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
Value *vp) Value *vp)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
AutoValueRooter rval(cx); AutoValueRooter rval(cx);
RootedValue call(cx, GetCall(proxy)); RootedValue call(cx, GetCall(proxy));
JSBool ok = Invoke(cx, vp[1], call, argc, JS_ARGV(cx, vp), rval.addr()); JSBool ok = Invoke(cx, vp[1], call, argc, JS_ARGV(cx, vp), rval.addr());
@ -303,6 +344,7 @@ bool
BaseProxyHandler::construct(JSContext *cx, JSObject *proxy_, unsigned argc, BaseProxyHandler::construct(JSContext *cx, JSObject *proxy_, unsigned argc,
Value *argv, Value *rval) Value *argv, Value *rval)
{ {
assertEnteredPolicy(cx, proxy_, JSID_VOID);
RootedObject proxy(cx, proxy_); RootedObject proxy(cx, proxy_);
RootedValue fval(cx, GetConstruct(proxy_)); RootedValue fval(cx, GetConstruct(proxy_));
if (fval.isUndefined()) if (fval.isUndefined())
@ -321,6 +363,7 @@ BaseProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
JSString * JSString *
BaseProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent) BaseProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
Value fval = GetCall(proxy); Value fval = GetCall(proxy);
if (IsFunctionProxy(proxy) && if (IsFunctionProxy(proxy) &&
(fval.isPrimitive() || !fval.toObject().isFunction())) { (fval.isPrimitive() || !fval.toObject().isFunction())) {
@ -366,6 +409,7 @@ BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl im
bool bool
BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
RootedValue val(cx, ObjectValue(*proxy.get())); RootedValue val(cx, ObjectValue(*proxy.get()));
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
JSDVG_SEARCH_STACK, val, NullPtr()); JSDVG_SEARCH_STACK, val, NullPtr());
@ -402,6 +446,8 @@ bool
DirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, DirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy,
jsid id, PropertyDescriptor *desc, unsigned flags) jsid id, PropertyDescriptor *desc, unsigned flags)
{ {
assertEnteredPolicy(cx, proxy, id);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
return JS_GetPropertyDescriptorById(cx, target, id, 0, desc); return JS_GetPropertyDescriptorById(cx, target, id, 0, desc);
} }
@ -426,6 +472,7 @@ bool
DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
jsid id, PropertyDescriptor *desc, unsigned flags) jsid id, PropertyDescriptor *desc, unsigned flags)
{ {
assertEnteredPolicy(cx, proxy, id);
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
return GetOwnPropertyDescriptor(cx, target, id, 0, desc); return GetOwnPropertyDescriptor(cx, target, id, 0, desc);
} }
@ -434,6 +481,7 @@ bool
DirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_, DirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
PropertyDescriptor *desc) PropertyDescriptor *desc)
{ {
assertEnteredPolicy(cx, proxy, id_);
RootedObject obj(cx, GetProxyTargetObject(proxy)); RootedObject obj(cx, GetProxyTargetObject(proxy));
Rooted<jsid> id(cx, id_); Rooted<jsid> id(cx, id_);
Rooted<Value> v(cx, desc->value); Rooted<Value> v(cx, desc->value);
@ -445,6 +493,7 @@ bool
DirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, DirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy,
AutoIdVector &props) AutoIdVector &props)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props); return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props);
} }
@ -453,6 +502,7 @@ bool
DirectProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) DirectProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{ {
RootedValue v(cx); RootedValue v(cx);
assertEnteredPolicy(cx, proxy, id);
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
if (!JS_DeletePropertyById2(cx, target, id, v.address())) if (!JS_DeletePropertyById2(cx, target, id, v.address()))
return false; return false;
@ -467,6 +517,8 @@ bool
DirectProxyHandler::enumerate(JSContext *cx, JSObject *proxy, DirectProxyHandler::enumerate(JSContext *cx, JSObject *proxy,
AutoIdVector &props) AutoIdVector &props)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
return GetPropertyNames(cx, target, 0, &props); return GetPropertyNames(cx, target, 0, &props);
} }
@ -488,6 +540,7 @@ bool
DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) bool *bp)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
JSBool b; JSBool b;
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
if (!JS_HasInstance(cx, target, v, &b)) if (!JS_HasInstance(cx, target, v, &b))
@ -508,6 +561,7 @@ DirectProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue,
JSString * JSString *
DirectProxyHandler::obj_toString(JSContext *cx, JSObject *proxy) DirectProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
return obj_toStringHelper(cx, GetProxyTargetObject(proxy)); return obj_toStringHelper(cx, GetProxyTargetObject(proxy));
} }
@ -515,6 +569,7 @@ JSString *
DirectProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, DirectProxyHandler::fun_toString(JSContext *cx, JSObject *proxy,
unsigned indent) unsigned indent)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
return fun_toStringHelper(cx, target, indent); return fun_toStringHelper(cx, target, indent);
} }
@ -550,6 +605,8 @@ DirectProxyHandler::DirectProxyHandler(void *family)
bool bool
DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{ {
assertEnteredPolicy(cx, proxy, id);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
JSBool found; JSBool found;
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
if (!JS_HasPropertyById(cx, target, id, &found)) if (!JS_HasPropertyById(cx, target, id, &found))
@ -561,6 +618,7 @@ DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
bool bool
DirectProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) DirectProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{ {
assertEnteredPolicy(cx, proxy, id);
RootedObject target(cx, GetProxyTargetObject(proxy)); RootedObject target(cx, GetProxyTargetObject(proxy));
AutoPropertyDescriptorRooter desc(cx); AutoPropertyDescriptorRooter desc(cx);
if (!JS_GetPropertyDescriptorById(cx, target, id, 0, &desc)) if (!JS_GetPropertyDescriptorById(cx, target, id, 0, &desc))
@ -573,6 +631,7 @@ bool
DirectProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_, DirectProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_,
jsid id_, Value *vp) jsid id_, Value *vp)
{ {
assertEnteredPolicy(cx, proxy, id_);
RootedObject receiver(cx, receiver_); RootedObject receiver(cx, receiver_);
RootedId id(cx, id_); RootedId id(cx, id_);
RootedValue value(cx); RootedValue value(cx);
@ -588,6 +647,7 @@ bool
DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg, DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg,
jsid id_, bool strict, Value *vp) jsid id_, bool strict, Value *vp)
{ {
assertEnteredPolicy(cx, proxy, id_);
RootedId id(cx, id_); RootedId id(cx, id_);
Rooted<JSObject*> receiver(cx, receiverArg); Rooted<JSObject*> receiver(cx, receiverArg);
RootedValue value(cx, *vp); RootedValue value(cx, *vp);
@ -602,6 +662,7 @@ DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg,
bool bool
DirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props) DirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
return GetPropertyNames(cx, GetProxyTargetObject(proxy), JSITER_OWNONLY, &props); return GetPropertyNames(cx, GetProxyTargetObject(proxy), JSITER_OWNONLY, &props);
} }
@ -609,6 +670,8 @@ bool
DirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags, DirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags,
Value *vp) Value *vp)
{ {
assertEnteredPolicy(cx, proxy, JSID_VOID);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy)); Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
RootedValue value(cx); RootedValue value(cx);
if (!GetIterator(cx, target, flags, &value)) if (!GetIterator(cx, target, flags, &value))

View File

@ -349,22 +349,66 @@ class JS_FRIEND_API(AutoEnterPolicy)
typedef BaseProxyHandler::Action Action; typedef BaseProxyHandler::Action Action;
AutoEnterPolicy(JSContext *cx, BaseProxyHandler *handler, AutoEnterPolicy(JSContext *cx, BaseProxyHandler *handler,
JSObject *wrapper, jsid id, Action act, bool mayThrow) JSObject *wrapper, jsid id, Action act, bool mayThrow)
#ifdef DEBUG
: context(NULL)
#endif
{ {
allow = handler->hasPolicy() ? handler->enter(cx, wrapper, id, act, &rv) allow = handler->hasPolicy() ? handler->enter(cx, wrapper, id, act, &rv)
: true; : true;
recordEnter(cx, wrapper, id);
if (!allow && !rv && mayThrow) if (!allow && !rv && mayThrow)
reportError(cx, id); reportError(cx, id);
} }
virtual ~AutoEnterPolicy() { recordLeave(); }
inline bool allowed() { return allow; } inline bool allowed() { return allow; }
inline bool returnValue() { JS_ASSERT(!allowed()); return rv; } inline bool returnValue() { JS_ASSERT(!allowed()); return rv; }
protected: protected:
// no-op constructor for subclass
AutoEnterPolicy()
#ifdef DEBUG
: context(NULL)
#endif
{};
void reportError(JSContext *cx, jsid id); void reportError(JSContext *cx, jsid id);
bool allow; bool allow;
bool rv; bool rv;
#ifdef DEBUG
JSContext *context;
mozilla::Maybe<RootedObject> enteredProxy;
mozilla::Maybe<RootedId> enteredId;
// NB: We explicitly don't track the entered action here, because sometimes
// SET traps do an implicit GET during their implementation, leading to
// spurious assertions.
AutoEnterPolicy *prev;
void recordEnter(JSContext *cx, JSObject *proxy, jsid id);
void recordLeave();
friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id);
#else
inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id) {}
inline void recordLeave() {}
#endif
}; };
#ifdef DEBUG
class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy {
public:
AutoWaivePolicy(JSContext *cx, JSObject *proxy, jsid id)
{
allow = true;
recordEnter(cx, proxy, id);
}
};
#else
class JS_FRIEND_API(AutoWaivePolicy) {
public: AutoWaivePolicy(JSContext *cx, JSObject *proxy, jsid id) {};
};
#endif
} /* namespace js */ } /* namespace js */
extern JS_FRIEND_API(JSObject *) extern JS_FRIEND_API(JSObject *)

View File

@ -126,54 +126,6 @@ Wrapper::~Wrapper()
{ {
} }
bool
Wrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapperArg,
jsid id, PropertyDescriptor *desc, unsigned flags)
{
RootedObject wrapper(cx, wrapperArg);
JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
return DirectProxyHandler::getPropertyDescriptor(cx, wrapper, id, desc, flags);
}
bool
Wrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapperArg,
jsid id, PropertyDescriptor *desc, unsigned flags)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags);
}
bool
Wrapper::defineProperty(JSContext *cx, JSObject *wrapperArg, jsid id,
PropertyDescriptor *desc)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::defineProperty(cx, wrapper, id, desc);
}
bool
Wrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapperArg,
AutoIdVector &props)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::getOwnPropertyNames(cx, wrapper, props);
}
bool
Wrapper::delete_(JSContext *cx, JSObject *wrapperArg, jsid id, bool *bp)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::delete_(cx, wrapper, id, bp);
}
bool
Wrapper::enumerate(JSContext *cx, JSObject *wrapperArg, AutoIdVector &props)
{
RootedObject wrapper(cx, wrapperArg);
JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
return DirectProxyHandler::enumerate(cx, wrapper, props);
}
/* /*
* Ordinarily, the convert trap would require unwrapping. However, the default * Ordinarily, the convert trap would require unwrapping. However, the default
* implementation of convert, JS_ConvertStub, obtains a default value by calling * implementation of convert, JS_ConvertStub, obtains a default value by calling
@ -208,95 +160,6 @@ Wrapper::defaultValue(JSContext *cx, JSObject *wrapperArg, JSType hint, Value *v
return DirectProxyHandler::defaultValue(cx, wrapper, hint, vp); return DirectProxyHandler::defaultValue(cx, wrapper, hint, vp);
} }
bool
Wrapper::has(JSContext *cx, JSObject *wrapperArg, jsid id, bool *bp)
{
RootedObject wrapper(cx, wrapperArg);
JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
return DirectProxyHandler::has(cx, wrapper, id, bp);
}
bool
Wrapper::hasOwn(JSContext *cx, JSObject *wrapperArg, jsid id, bool *bp)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::hasOwn(cx, wrapper, id, bp);
}
bool
Wrapper::get(JSContext *cx, JSObject *wrapperArg, JSObject *receiver, jsid id, Value *vp)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::get(cx, wrapper, receiver, id, vp);
}
bool
Wrapper::set(JSContext *cx, JSObject *wrapperArg, JSObject *receiver, jsid id, bool strict,
Value *vp)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::set(cx, wrapper, receiver, id, strict, vp);
}
bool
Wrapper::keys(JSContext *cx, JSObject *wrapperArg, AutoIdVector &props)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::keys(cx, wrapper, props);
}
bool
Wrapper::iterate(JSContext *cx, JSObject *wrapperArg, unsigned flags, Value *vp)
{
RootedObject wrapper(cx, wrapperArg);
JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
return DirectProxyHandler::iterate(cx, wrapper, flags, vp);
}
bool
Wrapper::call(JSContext *cx, JSObject *wrapperArg, unsigned argc, Value *vp)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::call(cx, wrapper, argc, vp);
}
bool
Wrapper::construct(JSContext *cx, JSObject *wrapperArg, unsigned argc, Value *argv, Value *vp)
{
RootedObject wrapper(cx, wrapperArg);
return DirectProxyHandler::construct(cx, wrapper, argc, argv, vp);
}
bool
Wrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
{
RootedObject wrapper(cx, &args.thisv().toObject());
// Note - we don't enter a policy here because our security architecture guards
// against nativeCall by overriding the trap itself in the right circumstances.
return DirectProxyHandler::nativeCall(cx, test, impl, args);
}
bool
Wrapper::hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, bool *bp)
{
return DirectProxyHandler::hasInstance(cx, wrapper, v, bp);
}
JSString *
Wrapper::obj_toString(JSContext *cx, JSObject *wrapperArg)
{
RootedObject wrapper(cx, wrapperArg);
JSString *str = DirectProxyHandler::obj_toString(cx, wrapper);
return str;
}
JSString *
Wrapper::fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent)
{
JSString *str = DirectProxyHandler::fun_toString(cx, wrapper, indent);
return str;
}
Wrapper Wrapper::singleton((unsigned)0); Wrapper Wrapper::singleton((unsigned)0);
Wrapper Wrapper::singletonWithPrototype((unsigned)0, true); Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);

View File

@ -66,38 +66,6 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
virtual ~Wrapper(); virtual ~Wrapper();
/* ES5 Harmony fundamental wrapper traps. */ /* ES5 Harmony fundamental wrapper traps. */
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
jsid id, PropertyDescriptor *desc,
unsigned flags) MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper,
jsid id, PropertyDescriptor *desc,
unsigned flags) MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
PropertyDescriptor *desc) MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
AutoIdVector &props) MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id,
bool *bp) MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, JSObject *wrapper,
AutoIdVector &props) MOZ_OVERRIDE;
/* ES5 Harmony derived wrapper traps. */
virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
Value *vp) MOZ_OVERRIDE;
virtual bool keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp) MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp) MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, Value *rval) MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, bool *bp) MOZ_OVERRIDE;
virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent) MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, JSObject *wrapper_, JSType hint, virtual bool defaultValue(JSContext *cx, JSObject *wrapper_, JSType hint,
Value *vp) MOZ_OVERRIDE; Value *vp) MOZ_OVERRIDE;

View File

@ -14,6 +14,8 @@ namespace xpc {
// their prototype, we have to instrument the traps to do this manually. // their prototype, we have to instrument the traps to do this manually.
ChromeObjectWrapper ChromeObjectWrapper::singleton; ChromeObjectWrapper ChromeObjectWrapper::singleton;
using js::assertEnteredPolicy;
static bool static bool
AllowedByBase(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) AllowedByBase(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act)
{ {
@ -58,6 +60,7 @@ ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
jsid id, js::PropertyDescriptor *desc, jsid id, js::PropertyDescriptor *desc,
unsigned flags) unsigned flags)
{ {
assertEnteredPolicy(cx, wrapper, id);
// First, try a lookup on the base wrapper if permitted. // First, try a lookup on the base wrapper if permitted.
desc->obj = NULL; desc->obj = NULL;
if (AllowedByBase(cx, wrapper, id, Wrapper::GET) && if (AllowedByBase(cx, wrapper, id, Wrapper::GET) &&
@ -87,6 +90,7 @@ ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
bool bool
ChromeObjectWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) ChromeObjectWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
{ {
assertEnteredPolicy(cx, wrapper, id);
// Try the lookup on the base wrapper if permitted. // Try the lookup on the base wrapper if permitted.
if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) && if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
!ChromeObjectWrapperBase::has(cx, wrapper, id, bp)) !ChromeObjectWrapperBase::has(cx, wrapper, id, bp))
@ -114,6 +118,7 @@ bool
ChromeObjectWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, ChromeObjectWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver,
jsid id, js::Value *vp) jsid id, js::Value *vp)
{ {
assertEnteredPolicy(cx, wrapper, id);
vp->setUndefined(); vp->setUndefined();
JSPropertyDescriptor desc; JSPropertyDescriptor desc;
// Only call through to the get trap on the underlying object if we're // Only call through to the get trap on the underlying object if we're
@ -155,7 +160,13 @@ ChromeObjectWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id,
// COWs fail silently for GETs, and that also happens to be the only case // COWs fail silently for GETs, and that also happens to be the only case
// where we might want to redirect the lookup to the home prototype chain. // where we might want to redirect the lookup to the home prototype chain.
*bp = (act == Wrapper::GET); *bp = (act == Wrapper::GET);
return *bp && PropIsFromStandardPrototype(cx, wrapper, id); if (!*bp || id == JSID_VOID)
return false;
// Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
// before we've fully entered the policy. Waive our policy.
js::AutoWaivePolicy policy(cx, wrapper, id);
return PropIsFromStandardPrototype(cx, wrapper, id);
} }
} }

View File

@ -63,6 +63,7 @@ bool
FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
js::PropertyDescriptor *desc, unsigned flags) js::PropertyDescriptor *desc, unsigned flags)
{ {
assertEnteredPolicy(cx, wrapper, id);
if (!Base::getPropertyDescriptor(cx, wrapper, id, desc, flags)) if (!Base::getPropertyDescriptor(cx, wrapper, id, desc, flags))
return false; return false;
return FilterSetter<Policy>(cx, wrapper, id, desc); return FilterSetter<Policy>(cx, wrapper, id, desc);
@ -74,6 +75,7 @@ FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, JSObject
js::PropertyDescriptor *desc, js::PropertyDescriptor *desc,
unsigned flags) unsigned flags)
{ {
assertEnteredPolicy(cx, wrapper, id);
if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags)) if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags))
return false; return false;
return FilterSetter<Policy>(cx, wrapper, id, desc); return FilterSetter<Policy>(cx, wrapper, id, desc);
@ -83,6 +85,7 @@ template <typename Base, typename Policy>
bool bool
FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
return Base::getOwnPropertyNames(cx, wrapper, props) && return Base::getOwnPropertyNames(cx, wrapper, props) &&
Filter<Policy>(cx, wrapper, props); Filter<Policy>(cx, wrapper, props);
} }
@ -91,6 +94,7 @@ template <typename Base, typename Policy>
bool bool
FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
return Base::enumerate(cx, wrapper, props) && return Base::enumerate(cx, wrapper, props) &&
Filter<Policy>(cx, wrapper, props); Filter<Policy>(cx, wrapper, props);
} }
@ -99,6 +103,7 @@ template <typename Base, typename Policy>
bool bool
FilteringWrapper<Base, Policy>::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) FilteringWrapper<Base, Policy>::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
return Base::keys(cx, wrapper, props) && return Base::keys(cx, wrapper, props) &&
Filter<Policy>(cx, wrapper, props); Filter<Policy>(cx, wrapper, props);
} }
@ -107,6 +112,7 @@ template <typename Base, typename Policy>
bool bool
FilteringWrapper<Base, Policy>::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp) FilteringWrapper<Base, Policy>::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
// We refuse to trigger the iterator hook across chrome wrappers because // We refuse to trigger the iterator hook across chrome wrappers because
// we don't know how to censor custom iterator objects. Instead we trigger // we don't know how to censor custom iterator objects. Instead we trigger
// the default proxy iterate trap, which will ask enumerate() for the list // the default proxy iterate trap, which will ask enumerate() for the list

View File

@ -1410,6 +1410,7 @@ bool
XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
js::PropertyDescriptor *desc, unsigned flags) js::PropertyDescriptor *desc, unsigned flags)
{ {
assertEnteredPolicy(cx, wrapper, id);
JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper); JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
if (Traits::isResolving(cx, holder, id)) { if (Traits::isResolving(cx, holder, id)) {
desc->obj = NULL; desc->obj = NULL;
@ -1528,6 +1529,7 @@ bool
XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
PropertyDescriptor *desc, unsigned flags) PropertyDescriptor *desc, unsigned flags)
{ {
assertEnteredPolicy(cx, wrapper, id);
JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper); JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
if (Traits::isResolving(cx, holder, id)) { if (Traits::isResolving(cx, holder, id)) {
desc->obj = NULL; desc->obj = NULL;
@ -1574,6 +1576,7 @@ bool
XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
js::PropertyDescriptor *desc) js::PropertyDescriptor *desc)
{ {
assertEnteredPolicy(cx, wrapper, id);
// Redirect access straight to the wrapper if we should be transparent. // Redirect access straight to the wrapper if we should be transparent.
if (XrayUtils::IsTransparent(cx, wrapper, id)) { if (XrayUtils::IsTransparent(cx, wrapper, id)) {
JSObject *obj = Traits::getTargetObject(wrapper); JSObject *obj = Traits::getTargetObject(wrapper);
@ -1626,6 +1629,7 @@ bool
XrayWrapper<Base, Traits>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, XrayWrapper<Base, Traits>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
JS::AutoIdVector &props) JS::AutoIdVector &props)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props); return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props);
} }
@ -1633,6 +1637,7 @@ template <typename Base, typename Traits>
bool bool
XrayWrapper<Base, Traits>::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) XrayWrapper<Base, Traits>::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
{ {
assertEnteredPolicy(cx, wrapper, id);
// Redirect access straight to the wrapper if we should be transparent. // Redirect access straight to the wrapper if we should be transparent.
if (XrayUtils::IsTransparent(cx, wrapper, id)) { if (XrayUtils::IsTransparent(cx, wrapper, id)) {
JSObject *obj = Traits::getTargetObject(wrapper); JSObject *obj = Traits::getTargetObject(wrapper);
@ -1669,6 +1674,7 @@ bool
XrayWrapper<Base, Traits>::enumerate(JSContext *cx, JSObject *wrapper, unsigned flags, XrayWrapper<Base, Traits>::enumerate(JSContext *cx, JSObject *wrapper, unsigned flags,
JS::AutoIdVector &props) JS::AutoIdVector &props)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
// Redirect access straight to the wrapper if we should be transparent. // Redirect access straight to the wrapper if we should be transparent.
if (XrayUtils::IsTransparent(cx, wrapper, JSID_VOID)) { if (XrayUtils::IsTransparent(cx, wrapper, JSID_VOID)) {
JSObject *obj = Traits::getTargetObject(wrapper); JSObject *obj = Traits::getTargetObject(wrapper);
@ -1762,6 +1768,7 @@ template <typename Base, typename Traits>
bool bool
XrayWrapper<Base, Traits>::call(JSContext *cx, JSObject *wrapper, unsigned argc, js::Value *vp) XrayWrapper<Base, Traits>::call(JSContext *cx, JSObject *wrapper, unsigned argc, js::Value *vp)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
return Traits::call(cx, wrapper, argc, vp); return Traits::call(cx, wrapper, argc, vp);
} }
@ -1770,6 +1777,7 @@ bool
XrayWrapper<Base, Traits>::construct(JSContext *cx, JSObject *wrapper, unsigned argc, XrayWrapper<Base, Traits>::construct(JSContext *cx, JSObject *wrapper, unsigned argc,
js::Value *argv, js::Value *rval) js::Value *argv, js::Value *rval)
{ {
assertEnteredPolicy(cx, wrapper, JSID_VOID);
return Traits::construct(cx, wrapper, argc, argv, rval); return Traits::construct(cx, wrapper, argc, argv, rval);
} }