mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1148188 - part2: interposeCall. r=billm
This commit is contained in:
parent
11fdde3a7d
commit
3ccaa7fa1e
@ -1261,6 +1261,13 @@ js::ForwardToNative(JSContext* cx, JSNative native, const CallArgs& args)
|
||||
return native(cx, args.length(), args.base());
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
js::ConvertArgsToArray(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
RootedObject argsArray(cx, NewDenseCopiedArray(cx, args.length(), args.array()));
|
||||
return argsArray;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSAtom*)
|
||||
js::GetPropertyNameFromPC(JSScript* script, jsbytecode* pc)
|
||||
{
|
||||
|
@ -2743,6 +2743,9 @@ extern JS_FRIEND_API(bool)
|
||||
DefineOwnProperty(JSContext* cx, JSObject* objArg, jsid idArg,
|
||||
JS::Handle<JSPropertyDescriptor> descriptor, JS::ObjectOpResult& result);
|
||||
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
|
@ -20,7 +20,7 @@
|
||||
* property, it should return a replacement property descriptor for it. If not,
|
||||
* it should return null.
|
||||
*/
|
||||
[scriptable,uuid(e5453950-d95a-11e3-9c1a-0800200c9a66)]
|
||||
[scriptable,uuid(215353cb-6e77-462f-a791-6891f42e593f)]
|
||||
interface nsIAddonInterposition : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -35,8 +35,23 @@ interface nsIAddonInterposition : nsISupports
|
||||
* @param prop The name of the property being accessed.
|
||||
* @return A property descriptor or null.
|
||||
*/
|
||||
jsval interpose(in jsval addonId,
|
||||
in jsval target,
|
||||
in nsIIDPtr iface,
|
||||
in jsval prop);
|
||||
jsval interposeProperty(in jsval addonId,
|
||||
in jsval target,
|
||||
in nsIIDPtr iface,
|
||||
in jsval prop);
|
||||
/**
|
||||
* We're intercepting calls from add-ons scopes into non-addon scopes.
|
||||
*
|
||||
* @param addonId The ID of the add-on accessing the property.
|
||||
* @param originalFunc The function object being intercepted.
|
||||
* @param originalThis The |this| value for the intercepted call.
|
||||
* @param args The arguments of the original call in an array.
|
||||
* @return The result of the call. NOTE: after the call interception,
|
||||
* the original function will not be called automatically, so the
|
||||
* implementer has to do that.
|
||||
*/
|
||||
jsval interposeCall(in jsval addonId,
|
||||
in jsval originalFunc,
|
||||
in jsval originalThis,
|
||||
in jsval args);
|
||||
};
|
||||
|
@ -123,7 +123,7 @@ interface ScheduledGCCallback : nsISupports
|
||||
/**
|
||||
* interface of Components.utils
|
||||
*/
|
||||
[scriptable, uuid(1a9bcb85-67a9-4a22-89a2-40eaf7fc31ec)]
|
||||
[scriptable, uuid(e04a4a58-2b5e-4a74-941a-0d344b057c5a)]
|
||||
interface nsIXPCComponents_Utils : nsISupports
|
||||
{
|
||||
|
||||
@ -689,6 +689,12 @@ interface nsIXPCComponents_Utils : nsISupports
|
||||
[implicit_jscontext]
|
||||
void setAddonInterposition(in ACString addonId, in nsIAddonInterposition interposition);
|
||||
|
||||
/*
|
||||
* Enables call interpositions from addon scopes to any functions in the scope of |target|.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
void setAddonCallInterposition(in jsval target);
|
||||
|
||||
/*
|
||||
* Return a fractional number of milliseconds from process
|
||||
* startup, measured with a monotonic clock.
|
||||
|
@ -3489,6 +3489,21 @@ nsXPCComponents_Utils::SetAddonInterposition(const nsACString& addonIdStr,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::SetAddonCallInterposition(HandleValue target,
|
||||
JSContext* cx)
|
||||
{
|
||||
NS_ENSURE_TRUE(target.isObject(), NS_ERROR_INVALID_ARG);
|
||||
RootedObject targetObj(cx, &target.toObject());
|
||||
targetObj = js::CheckedUnwrap(targetObj);
|
||||
NS_ENSURE_TRUE(targetObj, NS_ERROR_INVALID_ARG);
|
||||
XPCWrappedNativeScope* xpcScope = ObjectScope(targetObj);
|
||||
NS_ENSURE_TRUE(xpcScope, NS_ERROR_INVALID_ARG);
|
||||
|
||||
xpcScope->SetAddonCallInterposition();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::Now(double* aRetval)
|
||||
{
|
||||
|
@ -357,7 +357,7 @@ DefinePropertyIfFound(XPCCallContext& ccx,
|
||||
|
||||
if (scope->HasInterposition()) {
|
||||
Rooted<JSPropertyDescriptor> desc(ccx);
|
||||
if (!xpc::Interpose(ccx, obj, iface->GetIID(), id, &desc))
|
||||
if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc))
|
||||
return false;
|
||||
|
||||
if (desc.object()) {
|
||||
|
@ -83,6 +83,7 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
|
||||
mComponents(nullptr),
|
||||
mNext(nullptr),
|
||||
mGlobalJSObject(aGlobal),
|
||||
mHasCallInterpositions(false),
|
||||
mIsContentXBLScope(false),
|
||||
mIsAddonScope(false)
|
||||
{
|
||||
|
@ -1165,9 +1165,6 @@ public:
|
||||
js::PointerHasher<JSAddonId*, 3>,
|
||||
js::SystemAllocPolicy> InterpositionMap;
|
||||
|
||||
static bool SetAddonInterposition(JSAddonId* addonId,
|
||||
nsIAddonInterposition* interp);
|
||||
|
||||
// Gets the appropriate scope object for XBL in this scope. The context
|
||||
// must be same-compartment with the global upon entering, and the scope
|
||||
// object is wrapped into the compartment of the global.
|
||||
@ -1188,6 +1185,12 @@ public:
|
||||
bool HasInterposition() { return mInterposition; }
|
||||
nsCOMPtr<nsIAddonInterposition> GetInterposition();
|
||||
|
||||
static bool SetAddonInterposition(JSAddonId* addonId,
|
||||
nsIAddonInterposition* interp);
|
||||
|
||||
void SetAddonCallInterposition() { mHasCallInterpositions = true; }
|
||||
bool HasCallInterposition() { return mHasCallInterpositions; };
|
||||
|
||||
protected:
|
||||
virtual ~XPCWrappedNativeScope();
|
||||
|
||||
@ -1226,10 +1229,14 @@ private:
|
||||
// Lazily created sandboxes for addon code.
|
||||
nsTArray<JS::ObjectPtr> mAddonScopes;
|
||||
|
||||
// This is a service that will be use to interpose on all calls out of this
|
||||
// scope. If it's null, no interposition is done.
|
||||
// This is a service that will be use to interpose on some property accesses on
|
||||
// objects from other scope, for add-on compatibility reasons.
|
||||
nsCOMPtr<nsIAddonInterposition> mInterposition;
|
||||
|
||||
// If this flag is set, we intercept function calls on vanilla JS function objects
|
||||
// from this scope if the caller scope has mInterposition set.
|
||||
bool mHasCallInterpositions;
|
||||
|
||||
nsAutoPtr<DOMExpandoSet> mDOMExpandoSet;
|
||||
|
||||
JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
|
||||
|
@ -34,7 +34,7 @@ let TestInterposition = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonInterposition,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
interpose: function(addonId, target, iid, prop) {
|
||||
interposeProperty: function(addonId, target, iid, prop) {
|
||||
do_check_eq(addonId, ADDONID);
|
||||
do_check_eq(gExpectedProp, prop);
|
||||
gExpectedProp = undefined;
|
||||
@ -56,6 +56,12 @@ let TestInterposition = {
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
interposeCall: function(addonId, originalFunc, originalThis, args) {
|
||||
do_check_eq(addonId, ADDONID);
|
||||
args.splice(0, 0, addonId);
|
||||
return originalFunc.apply(originalThis, args);
|
||||
}
|
||||
};
|
||||
|
||||
@ -138,5 +144,17 @@ function run_test()
|
||||
do_check_eq(desc.configurable, false);
|
||||
});
|
||||
|
||||
let moduleScope = Cu.Sandbox(this);
|
||||
moduleScope.ADDONID = ADDONID;
|
||||
moduleScope.do_check_eq = do_check_eq;
|
||||
function funToIntercept(addonId) {
|
||||
do_check_eq(addonId, ADDONID);
|
||||
counter++;
|
||||
}
|
||||
sandbox.moduleFunction = Cu.evalInSandbox(funToIntercept.toSource() + "; funToIntercept", moduleScope);
|
||||
Cu.evalInSandbox("var counter = 0;", moduleScope);
|
||||
Cu.evalInSandbox("Components.utils.setAddonCallInterposition(this);", moduleScope);
|
||||
Cu.evalInSandbox("moduleFunction()", sandbox);
|
||||
do_check_eq(Cu.evalInSandbox("counter", moduleScope), 1);
|
||||
Cu.setAddonInterposition(ADDONID, null);
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ using namespace JS;
|
||||
namespace xpc {
|
||||
|
||||
bool
|
||||
Interpose(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> descriptor)
|
||||
InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> descriptor)
|
||||
{
|
||||
// We only want to do interpostion on DOM instances and
|
||||
// wrapped natives.
|
||||
@ -45,8 +45,8 @@ Interpose(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
|
||||
RootedValue prop(cx, IdToValue(id));
|
||||
RootedValue targetValue(cx, ObjectValue(*target));
|
||||
RootedValue descriptorVal(cx);
|
||||
nsresult rv = interp->Interpose(addonIdValue, targetValue,
|
||||
iid, prop, &descriptorVal);
|
||||
nsresult rv = interp->InterposeProperty(addonIdValue, targetValue,
|
||||
iid, prop, &descriptorVal);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
@ -79,12 +79,64 @@ Interpose(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
InterposeCall(JSContext* cx, JS::HandleObject target, const JS::CallArgs& args, bool* done)
|
||||
{
|
||||
*done = false;
|
||||
XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx));
|
||||
MOZ_ASSERT(scope->HasInterposition());
|
||||
|
||||
nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
|
||||
|
||||
RootedObject unwrappedTarget(cx, UncheckedUnwrap(target));
|
||||
XPCWrappedNativeScope* targetScope = ObjectScope(unwrappedTarget);
|
||||
bool hasInterpostion = targetScope->HasCallInterposition();
|
||||
|
||||
if (!hasInterpostion)
|
||||
return true;
|
||||
|
||||
// If there is a call interpostion, we don't want to propogate the
|
||||
// call to Base:
|
||||
*done = true;
|
||||
|
||||
JSAddonId* addonId = AddonIdOfObject(target);
|
||||
RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId)));
|
||||
RootedValue targetValue(cx, ObjectValue(*target));
|
||||
RootedValue thisValue(cx, args.thisv());
|
||||
RootedObject argsArray(cx, ConvertArgsToArray(cx, args));
|
||||
if (!argsArray)
|
||||
return false;
|
||||
|
||||
RootedValue argsVal(cx, ObjectValue(*argsArray));
|
||||
RootedValue returnVal(cx);
|
||||
|
||||
nsresult rv = interp->InterposeCall(addonIdValue, targetValue,
|
||||
thisValue, argsVal, args.rval());
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool AddonWrapper<Base>::call(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
const JS::CallArgs& args) const
|
||||
{
|
||||
bool done = false;
|
||||
if (!InterposeCall(cx, wrapper, args, &done))
|
||||
return false;
|
||||
|
||||
return done || Base::call(cx, wrapper, args);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
bool
|
||||
AddonWrapper<Base>::getPropertyDescriptor(JSContext* cx, HandleObject wrapper,
|
||||
HandleId id, MutableHandle<JSPropertyDescriptor> desc) const
|
||||
{
|
||||
if (!Interpose(cx, wrapper, nullptr, id, desc))
|
||||
if (!InterposeProperty(cx, wrapper, nullptr, id, desc))
|
||||
return false;
|
||||
|
||||
if (desc.object())
|
||||
@ -98,7 +150,7 @@ bool
|
||||
AddonWrapper<Base>::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper,
|
||||
HandleId id, MutableHandle<JSPropertyDescriptor> desc) const
|
||||
{
|
||||
if (!Interpose(cx, wrapper, nullptr, id, desc))
|
||||
if (!InterposeProperty(cx, wrapper, nullptr, id, desc))
|
||||
return false;
|
||||
|
||||
if (desc.object())
|
||||
@ -113,7 +165,7 @@ AddonWrapper<Base>::get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle
|
||||
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const
|
||||
{
|
||||
Rooted<JSPropertyDescriptor> desc(cx);
|
||||
if (!Interpose(cx, wrapper, nullptr, id, &desc))
|
||||
if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
|
||||
return false;
|
||||
|
||||
if (!desc.object())
|
||||
@ -136,7 +188,7 @@ AddonWrapper<Base>::set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id
|
||||
JS::HandleValue receiver, JS::ObjectOpResult& result) const
|
||||
{
|
||||
Rooted<JSPropertyDescriptor> desc(cx);
|
||||
if (!Interpose(cx, wrapper, nullptr, id, &desc))
|
||||
if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
|
||||
return false;
|
||||
|
||||
if (!desc.object())
|
||||
@ -164,7 +216,7 @@ AddonWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, HandleId
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
Rooted<JSPropertyDescriptor> interpDesc(cx);
|
||||
if (!Interpose(cx, wrapper, nullptr, id, &interpDesc))
|
||||
if (!InterposeProperty(cx, wrapper, nullptr, id, &interpDesc))
|
||||
return false;
|
||||
|
||||
if (!interpDesc.object())
|
||||
@ -180,7 +232,7 @@ AddonWrapper<Base>::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
Rooted<JSPropertyDescriptor> desc(cx);
|
||||
if (!Interpose(cx, wrapper, nullptr, id, &desc))
|
||||
if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
|
||||
return false;
|
||||
|
||||
if (!desc.object())
|
||||
|
@ -16,8 +16,12 @@
|
||||
namespace xpc {
|
||||
|
||||
bool
|
||||
Interpose(JSContext* cx, JS::HandleObject target, const nsIID* iid, JS::HandleId id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> descriptor);
|
||||
InterposeProperty(JSContext* cx, JS::HandleObject target, const nsIID* iid, JS::HandleId id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> descriptor);
|
||||
|
||||
bool
|
||||
InterposeCall(JSContext* cx, JS::HandleObject wrapper,
|
||||
const JS::CallArgs& args, bool& done);
|
||||
|
||||
template<typename Base>
|
||||
class AddonWrapper : public Base {
|
||||
@ -36,6 +40,8 @@ class AddonWrapper : public Base {
|
||||
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
|
||||
virtual bool set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult& result) const override;
|
||||
virtual bool call(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
const JS::CallArgs& args) const override;
|
||||
|
||||
virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<jsid> id,
|
||||
|
@ -22,9 +22,14 @@ DefaultInterpositionService.prototype = {
|
||||
classID: Components.ID("{50bc93ce-602a-4bef-bf3a-61fc749c4caf}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonInterposition, Ci.nsISupportsWeakReference]),
|
||||
|
||||
interpose: function(addon, target, iid, prop) {
|
||||
interposeProperty: function(addon, target, iid, prop) {
|
||||
return null;
|
||||
},
|
||||
|
||||
interposeCall: function(addonId, originalFunc, originalThis, args) {
|
||||
args.splice(0, 0, addonId);
|
||||
return originalFunc.apply(originalThis, args);
|
||||
},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DefaultInterpositionService]);
|
||||
|
@ -105,7 +105,7 @@ AddonInterpositionService.prototype = {
|
||||
return "generic";
|
||||
},
|
||||
|
||||
interpose: function(addon, target, iid, prop) {
|
||||
interposeProperty: function(addon, target, iid, prop) {
|
||||
let interp;
|
||||
if (iid) {
|
||||
interp = this._interfaceInterpositions[iid];
|
||||
@ -143,6 +143,11 @@ AddonInterpositionService.prototype = {
|
||||
|
||||
return Prefetcher.lookupInCache(addon, target, prop);
|
||||
},
|
||||
|
||||
interposeCall: function(addonId, originalFunc, originalThis, args) {
|
||||
args.splice(0, 0, addonId);
|
||||
return originalFunc.apply(originalThis, args);
|
||||
},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AddonInterpositionService]);
|
||||
|
Loading…
Reference in New Issue
Block a user