Backed out changesets 63671ebfa2dd and da3d272ad1c2 (bug 1164011) for frequent xpc::InterposeProperty crashes.

This commit is contained in:
Ryan VanderMeulen 2015-05-29 12:51:34 -04:00
parent ca1661674b
commit 004203a4be
11 changed files with 18 additions and 203 deletions

View File

@ -436,7 +436,6 @@
@RESPATH@/components/nsUpdateTimerManager.js
@RESPATH@/components/addoncompat.manifest
@RESPATH@/components/multiprocessShims.js
@RESPATH@/components/defaultShims.js
@RESPATH@/components/remoteTagService.js
@RESPATH@/components/pluginGlue.manifest
@RESPATH@/components/ProcessSingleton.manifest

View File

@ -20,7 +20,7 @@
* property, it should return a replacement property descriptor for it. If not,
* it should return null.
*/
[scriptable,uuid(d05cc5fd-ad88-41a6-854c-36fd94d69ddb)]
[scriptable,uuid(215353cb-6e77-462f-a791-6891f42e593f)]
interface nsIAddonInterposition : nsISupports
{
/**
@ -54,14 +54,4 @@ interface nsIAddonInterposition : nsISupports
in jsval originalFunc,
in jsval originalThis,
in jsval args);
/**
* For the first time when the interposition is registered the engine
* calls getWhitelist and expects an array of strings. The strings are
* the name of properties the interposition wants interposeProperty
* to be called. It can be an empty array.
* Note: for CPOWs interposeProperty is always called regardless if
* the name of the property is on the whitelist or not.
*/
jsval getWhitelist();
};

View File

@ -32,7 +32,6 @@
#include "nsWindowMemoryReporter.h"
#include "nsDOMClassInfo.h"
#include "ShimInterfaceInfo.h"
#include "nsIAddonInterposition.h"
using namespace mozilla;
using namespace JS;
@ -3491,9 +3490,8 @@ nsXPCComponents_Utils::SetAddonInterposition(const nsACString& addonIdStr,
JSAddonId* addonId = xpc::NewAddonId(cx, addonIdStr);
if (!addonId)
return NS_ERROR_FAILURE;
if (!XPCWrappedNativeScope::SetAddonInterposition(cx, addonId, interposition))
if (!XPCWrappedNativeScope::SetAddonInterposition(addonId, interposition))
return NS_ERROR_FAILURE;
return NS_OK;
}

View File

@ -27,7 +27,6 @@ using namespace JS;
XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
XPCWrappedNativeScope::InterpositionMap* XPCWrappedNativeScope::gInterpositionMap = nullptr;
InterpositionWhitelistArray* XPCWrappedNativeScope::gInterpositionWhitelists = nullptr;
NS_IMPL_ISUPPORTS(XPCWrappedNativeScope::ClearInterpositionsObserver, nsIObserver)
@ -47,11 +46,6 @@ XPCWrappedNativeScope::ClearInterpositionsObserver::Observe(nsISupports* subject
gInterpositionMap = nullptr;
}
if (gInterpositionWhitelists) {
delete gInterpositionWhitelists;
gInterpositionWhitelists = nullptr;
}
nsContentUtils::UnregisterShutdownObserver(this);
return NS_OK;
}
@ -149,8 +143,6 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
"extensions.interposition.enabled", false);
if (interpositionEnabled) {
mInterposition = do_GetService("@mozilla.org/addons/default-addon-shims;1");
MOZ_ASSERT(mInterposition);
UpdateInterpositionWhitelist(cx, mInterposition);
}
}
}
@ -764,8 +756,7 @@ XPCWrappedNativeScope::SetExpandoChain(JSContext* cx, HandleObject target,
}
/* static */ bool
XPCWrappedNativeScope::SetAddonInterposition(JSContext* cx,
JSAddonId* addonId,
XPCWrappedNativeScope::SetAddonInterposition(JSAddonId* addonId,
nsIAddonInterposition* interp)
{
if (!gInterpositionMap) {
@ -773,17 +764,14 @@ XPCWrappedNativeScope::SetAddonInterposition(JSContext* cx,
gInterpositionMap->init();
// Make sure to clear the map at shutdown.
// Note: this will take care of gInterpositionWhitelists too.
nsContentUtils::RegisterShutdownObserver(new ClearInterpositionsObserver());
}
if (interp) {
bool ok = gInterpositionMap->put(addonId, interp);
NS_ENSURE_TRUE(ok, false);
UpdateInterpositionWhitelist(cx, interp);
return gInterpositionMap->put(addonId, interp);
} else {
gInterpositionMap->remove(addonId);
return true;
}
return true;
}
nsCOMPtr<nsIAddonInterposition>
@ -792,103 +780,6 @@ XPCWrappedNativeScope::GetInterposition()
return mInterposition;
}
/* static */ InterpositionWhitelist*
XPCWrappedNativeScope::GetInterpositionWhitelist(nsIAddonInterposition* interposition)
{
if (!gInterpositionWhitelists)
return nullptr;
InterpositionWhitelistArray& wls = *gInterpositionWhitelists;
for (size_t i = 0; i < wls.Length(); i++) {
if (wls[i].interposition == interposition)
return &wls[i].whitelist;
}
return nullptr;
}
/* static */ bool
XPCWrappedNativeScope::UpdateInterpositionWhitelist(JSContext* cx,
nsIAddonInterposition* interposition)
{
// We want to set the interpostion whitelist only once.
InterpositionWhitelist* whitelist = GetInterpositionWhitelist(interposition);
if (whitelist)
return true;
// The hashsets in gInterpositionWhitelists do not have a copy constructor so
// a reallocation for the array will lead to a memory corruption. If you
// need more interpositions, change the capacity of the array please.
static const size_t MAX_INTERPOSITION = 8;
if (!gInterpositionWhitelists)
gInterpositionWhitelists = new InterpositionWhitelistArray(MAX_INTERPOSITION);
MOZ_RELEASE_ASSERT(MAX_INTERPOSITION > gInterpositionWhitelists->Length() + 1);
InterpositionWhitelistPair* newPair = gInterpositionWhitelists->AppendElement();
newPair->interposition = interposition;
newPair->whitelist.init();
whitelist = &newPair->whitelist;
RootedValue whitelistVal(cx);
nsresult rv = interposition->GetWhitelist(&whitelistVal);
if (NS_FAILED(rv)) {
JS_ReportError(cx, "Could not get the whitelist from the interposition.");
return false;
}
if (!whitelistVal.isObject()) {
JS_ReportError(cx, "Whitelist must be an array.");
return false;
}
// We want to enter the whitelist's compartment to avoid any wrappers.
// To be on the safe side let's make sure that it's a system compartment
// and we don't accidentally trigger some content function here by parsing
// the whitelist object.
RootedObject whitelistObj(cx, &whitelistVal.toObject());
whitelistObj = js::UncheckedUnwrap(whitelistObj);
if (!AccessCheck::isChrome(whitelistObj)) {
JS_ReportError(cx, "Whitelist must be from system scope.");
return false;
}
{
JSAutoCompartment ac(cx, whitelistObj);
uint32_t length;
if (!JS_IsArrayObject(cx, whitelistObj) ||
!JS_GetArrayLength(cx, whitelistObj, &length)) {
JS_ReportError(cx, "Whitelist must be an array.");
return false;
}
for (uint32_t i = 0; i < length; i++) {
RootedValue idval(cx);
if (!JS_GetElement(cx, whitelistObj, i, &idval))
return false;
if (!idval.isString()) {
JS_ReportError(cx, "Whitelist must contain strings only.");
return false;
}
RootedString str(cx, idval.toString());
str = JS_InternJSString(cx, str);
if (!str) {
JS_ReportError(cx, "String internization failed.");
return false;
}
// By internizing the id's we ensure that they won't get
// GCed so we can use them as hash keys.
jsid id = INTERNED_STRING_TO_JSID(cx, str);
whitelist->put(JSID_BITS(id));
}
}
return true;
}
/***************************************************************************/
// static

View File

@ -1360,14 +1360,17 @@ bool
SetAddonInterposition(const nsACString& addonIdStr, nsIAddonInterposition* interposition)
{
JSAddonId* addonId;
// We enter the junk scope just to allocate a string, which actually will go
// in the system zone.
AutoJSAPI jsapi;
jsapi.Init(xpc::PrivilegedJunkScope());
addonId = NewAddonId(jsapi.cx(), addonIdStr);
if (!addonId)
return false;
return XPCWrappedNativeScope::SetAddonInterposition(jsapi.cx(), addonId, interposition);
{
// We enter the junk scope just to allocate a string, which actually will go
// in the system zone.
AutoJSAPI jsapi;
jsapi.Init(xpc::PrivilegedJunkScope());
addonId = NewAddonId(jsapi.cx(), addonIdStr);
if (!addonId)
return false;
}
return XPCWrappedNativeScope::SetAddonInterposition(addonId, interposition);
}
} // namespace xpc

View File

@ -1018,17 +1018,6 @@ static inline bool IS_PROTO_CLASS(const js::Class* clazz)
clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
}
typedef js::HashSet<uint64_t,
js::DefaultHasher<uint64_t>,
js::SystemAllocPolicy> InterpositionWhitelist;
struct InterpositionWhitelistPair {
nsIAddonInterposition* interposition;
InterpositionWhitelist whitelist;
};
typedef nsTArray<InterpositionWhitelistPair> InterpositionWhitelistArray;
/***************************************************************************/
// XPCWrappedNativeScope is one-to-one with a JS global object.
@ -1198,14 +1187,9 @@ public:
bool HasInterposition() { return mInterposition; }
nsCOMPtr<nsIAddonInterposition> GetInterposition();
static bool SetAddonInterposition(JSContext* cx,
JSAddonId* addonId,
static bool SetAddonInterposition(JSAddonId* addonId,
nsIAddonInterposition* interp);
static InterpositionWhitelist* GetInterpositionWhitelist(nsIAddonInterposition* interposition);
static bool UpdateInterpositionWhitelist(JSContext* cx,
nsIAddonInterposition* interposition);
void SetAddonCallInterposition() { mHasCallInterpositions = true; }
bool HasCallInterposition() { return mHasCallInterpositions; };
@ -1228,8 +1212,6 @@ private:
static InterpositionMap* gInterpositionMap;
static InterpositionWhitelistArray* gInterpositionWhitelists;
XPCJSRuntime* mRuntime;
Native2WrappedNativeMap* mWrappedNativeMap;
ClassInfo2WrappedNativeProtoMap* mWrappedNativeProtoMap;

View File

@ -34,11 +34,6 @@ let TestInterposition = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonInterposition,
Ci.nsISupportsWeakReference]),
getWhitelist: function() {
return ["abcxyz", "utils", "dataprop", "getterprop", "setterprop",
"objprop", "defineprop", "configurableprop"];
},
interposeProperty: function(addonId, target, iid, prop) {
do_check_eq(addonId, ADDONID);
do_check_eq(gExpectedProp, prop);

View File

@ -29,12 +29,11 @@ InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId
// wrapped natives.
RootedObject unwrapped(cx, UncheckedUnwrap(target));
const js::Class* clasp = js::GetObjectClass(unwrapped);
bool isCPOW = jsipc::IsWrappedCPOW(unwrapped);
if (!mozilla::dom::IsDOMClass(clasp) &&
!IS_WN_CLASS(clasp) &&
!IS_PROTO_CLASS(clasp) &&
clasp != &OuterWindowProxyClass &&
!isCPOW) {
!jsipc::IsWrappedCPOW(unwrapped)) {
return true;
}
@ -42,13 +41,6 @@ InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId
MOZ_ASSERT(scope->HasInterposition());
nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
InterpositionWhitelist* wl = XPCWrappedNativeScope::GetInterpositionWhitelist(interp);
MOZ_ASSERT(wl);
// We do InterposeProperty only if the id is on the whitelist of the interpostion
// or if the target is a CPOW.
if (!wl->has(JSID_BITS(id.get())) && !isCPOW)
return true;
JSAddonId* addonId = AddonIdOfObject(target);
RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId)));
RootedValue prop(cx, IdToValue(id));

View File

@ -22,10 +22,6 @@ DefaultInterpositionService.prototype = {
classID: Components.ID("{50bc93ce-602a-4bef-bf3a-61fc749c4caf}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonInterposition, Ci.nsISupportsWeakReference]),
getWhitelist: function() {
return [];
},
interposeProperty: function(addon, target, iid, prop) {
return null;
},

View File

@ -8,7 +8,6 @@ TEST_DIRS += ['tests']
EXTRA_COMPONENTS += [
'addoncompat.manifest',
'defaultShims.js',
'multiprocessShims.js',
'remoteTagService.js',
]

View File

@ -70,42 +70,12 @@ function AddonInterpositionService()
// kinds of objects.
this._interfaceInterpositions = RemoteAddonsParent.getInterfaceInterpositions();
this._taggedInterpositions = RemoteAddonsParent.getTaggedInterpositions();
let wl = [];
for (let v in this._interfaceInterpositions) {
let interp = this._interfaceInterpositions[v];
wl.push(...Object.getOwnPropertyNames(interp.methods));
wl.push(...Object.getOwnPropertyNames(interp.getters));
wl.push(...Object.getOwnPropertyNames(interp.setters));
}
for (let v in this._taggedInterpositions) {
let interp = this._taggedInterpositions[v];
wl.push(...Object.getOwnPropertyNames(interp.methods));
wl.push(...Object.getOwnPropertyNames(interp.getters));
wl.push(...Object.getOwnPropertyNames(interp.setters));
}
let nameSet = new Set();
wl = wl.filter(function(item) {
if (nameSet.has(item))
return true;
nameSet.add(item);
return true;
});
this._whitelist = wl;
}
AddonInterpositionService.prototype = {
classID: Components.ID("{1363d5f0-d95e-11e3-9c1a-0800200c9a66}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonInterposition, Ci.nsISupportsWeakReference]),
getWhitelist: function() {
return this._whitelist;
},
// When the interface is not known for a method call, this code
// determines the type of the target object.
getObjectTag: function(target) {