mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1159469 - Make sure public jsapi Map/Set calls deal with compartments/proxies; r=bz r=jorendorff
This commit is contained in:
parent
f863dc86c7
commit
235976fe9b
@ -2220,6 +2220,7 @@ static
|
||||
bool
|
||||
forEach(const char* funcName, JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisArg)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
RootedId forEachId(cx, NameToId(cx->names().forEach));
|
||||
RootedFunction forEachFunc(cx, JS::GetSelfHostedFunction(cx, funcName, forEachId, 2));
|
||||
if (!forEachFunc)
|
||||
@ -2234,6 +2235,77 @@ forEach(const char* funcName, JSContext *cx, HandleObject obj, HandleValue callb
|
||||
return Invoke(cx, args);
|
||||
}
|
||||
|
||||
// Handles Clear/Size for public jsapi map/set access
|
||||
template<typename RetT>
|
||||
RetT
|
||||
CallObjFunc(RetT(*ObjFunc)(JSContext*, HandleObject), JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
// Always unwrap, in case this is an xray or cross-compartment wrapper.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
|
||||
// Enter the compartment of the backing object before calling functions on
|
||||
// it.
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
return ObjFunc(cx, unwrappedObj);
|
||||
}
|
||||
|
||||
// Handles Has/Delete for public jsapi map/set access
|
||||
bool
|
||||
CallObjFunc(bool(*ObjFunc)(JSContext *cx, HandleObject obj, HandleValue key, bool *rval),
|
||||
JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, key);
|
||||
|
||||
// Always unwrap, in case this is an xray or cross-compartment wrapper.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
|
||||
// If we're working with a wrapped map/set, rewrap the key into the
|
||||
// compartment of the unwrapped map/set.
|
||||
RootedValue wrappedKey(cx, key);
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey))
|
||||
return false;
|
||||
}
|
||||
return ObjFunc(cx, unwrappedObj, wrappedKey, rval);
|
||||
}
|
||||
|
||||
// Handles iterator generation for public jsapi map/set access
|
||||
template<typename Iter>
|
||||
bool
|
||||
CallObjFunc(bool(*ObjFunc)(JSContext* cx, Iter kind,
|
||||
HandleObject obj, MutableHandleValue iter),
|
||||
JSContext *cx, Iter iterType, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
// Always unwrap, in case this is an xray or cross-compartment wrapper.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
// Retrieve the iterator while in the unwrapped map/set's compartment,
|
||||
// otherwise we'll crash on a compartment assert.
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
if (!ObjFunc(cx, iterType, unwrappedObj, rval))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the caller is in a different compartment than the map/set, rewrap the
|
||||
// iterator object into the caller's compartment.
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, rval))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** JS public APIs **********************************************************/
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
@ -2245,78 +2317,106 @@ JS::NewMapObject(JSContext* cx)
|
||||
JS_PUBLIC_API(uint32_t)
|
||||
JS::MapSize(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return MapObject::size(cx, obj);
|
||||
return CallObjFunc<uint32_t>(&MapObject::size, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapGet(JSContext* cx, HandleObject obj,
|
||||
HandleValue key, MutableHandleValue rval)
|
||||
JS::MapGet(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key, rval);
|
||||
return MapObject::get(cx, obj, key, rval);
|
||||
assertSameCompartment(cx, obj, key, rval);
|
||||
|
||||
// Unwrap the object, and enter its compartment. If object isn't wrapped,
|
||||
// this is essentially a noop.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
RootedValue wrappedKey(cx, key);
|
||||
|
||||
// If we passed in a wrapper, wrap our key into its compartment now.
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey))
|
||||
return false;
|
||||
}
|
||||
if (!MapObject::get(cx, unwrappedObj, wrappedKey, rval))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we passed in a wrapper, wrap our return value on the way out.
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, rval))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapSet(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, key, val);
|
||||
|
||||
// Unwrap the object, and enter its compartment. If object isn't wrapped,
|
||||
// this is essentially a noop.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
|
||||
// If we passed in a wrapper, wrap both key and value before adding to
|
||||
// the map
|
||||
RootedValue wrappedKey(cx, key);
|
||||
RootedValue wrappedValue(cx, val);
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey) ||
|
||||
!JS_WrapValue(cx, &wrappedValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return MapObject::set(cx, unwrappedObj, wrappedKey, wrappedValue);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key);
|
||||
return MapObject::has(cx, obj, key, rval);
|
||||
return CallObjFunc(MapObject::has, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
JS::MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key);
|
||||
return MapObject::delete_(cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapSet(JSContext *cx, HandleObject obj,
|
||||
HandleValue key, HandleValue val)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key, val);
|
||||
return MapObject::set(cx, obj, key, val);
|
||||
return CallObjFunc(MapObject::delete_, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapClear(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return MapObject::clear(cx, obj);
|
||||
return CallObjFunc(&MapObject::clear, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return MapObject::iterator(cx, MapObject::Keys, obj, rval);
|
||||
return CallObjFunc(&MapObject::iterator, cx, MapObject::Keys, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return MapObject::iterator(cx, MapObject::Values, obj, rval);
|
||||
return CallObjFunc(&MapObject::iterator, cx, MapObject::Values, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return MapObject::iterator(cx, MapObject::Entries, obj, rval);
|
||||
return CallObjFunc(&MapObject::iterator, cx, MapObject::Entries, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return forEach("MapForEach", cx, obj, callbackFn, thisVal);
|
||||
}
|
||||
|
||||
@ -2329,66 +2429,70 @@ JS::NewSetObject(JSContext *cx)
|
||||
JS_PUBLIC_API(uint32_t)
|
||||
JS::SetSize(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return SetObject::size(cx, obj);
|
||||
return CallObjFunc<uint32_t>(&SetObject::size, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetHas(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
JS::SetAdd(JSContext *cx, HandleObject obj, HandleValue key)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key);
|
||||
return SetObject::has(cx, obj, key, rval);
|
||||
assertSameCompartment(cx, obj, key);
|
||||
|
||||
// Unwrap the object, and enter its compartment. If object isn't wrapped,
|
||||
// this is essentially a noop.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
|
||||
// If we passed in a wrapper, wrap key before adding to the set
|
||||
RootedValue wrappedKey(cx, key);
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey))
|
||||
return false;
|
||||
}
|
||||
return SetObject::add(cx, unwrappedObj, wrappedKey);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
return CallObjFunc(SetObject::has, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key);
|
||||
return SetObject::delete_(cx, obj, key, rval);
|
||||
return CallObjFunc(SetObject::delete_, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetAdd(JSContext *cx, HandleObject obj,
|
||||
HandleValue key)
|
||||
JS::SetClear(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key);
|
||||
return SetObject::add(cx, obj, key);
|
||||
return CallObjFunc(&SetObject::clear, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetClear(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return SetObject::clear(cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetKeys(JSContext *cx, HandleObject obj, MutableHandleValue rval)
|
||||
JS::SetKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
return SetValues(cx, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetValues(JSContext *cx, HandleObject obj, MutableHandleValue rval)
|
||||
JS::SetValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return SetObject::iterator(cx, SetObject::Values, obj, rval);
|
||||
return CallObjFunc(&SetObject::iterator, cx, SetObject::Values, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetEntries(JSContext *cx, HandleObject obj, MutableHandleValue rval)
|
||||
JS::SetEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return SetObject::iterator(cx, SetObject::Entries, obj, rval);
|
||||
return CallObjFunc(&SetObject::iterator, cx, SetObject::Entries, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return forEach("SetForEach", cx, obj, callbackFn, thisVal);
|
||||
}
|
||||
|
@ -98,10 +98,16 @@ class MapObject : public NativeObject {
|
||||
static bool has(JSContext* cx, unsigned argc, Value* vp);
|
||||
static MapObject* create(JSContext* cx);
|
||||
|
||||
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
|
||||
// interfaces, etc.)
|
||||
static uint32_t size(JSContext *cx, HandleObject obj);
|
||||
static bool get(JSContext *cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
|
||||
static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
|
||||
// Set call for public JSAPI exposure. Does not actually return map object
|
||||
// as stated in spec, expects caller to return a value. for instance, with
|
||||
// webidl maplike/setlike, should return interface object.
|
||||
static bool set(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val);
|
||||
static bool clear(JSContext *cx, HandleObject obj);
|
||||
static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
|
||||
@ -151,6 +157,8 @@ class SetObject : public NativeObject {
|
||||
static bool add(JSContext *cx, HandleObject obj, HandleValue key);
|
||||
static bool has(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
// Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
|
||||
// interfaces, etc.)
|
||||
static SetObject* create(JSContext *cx);
|
||||
static uint32_t size(JSContext *cx, HandleObject obj);
|
||||
static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
|
Loading…
Reference in New Issue
Block a user