Bug 563106 - Tie XPConnect to compartments. r=jorendorff/gal/jst

This commit is contained in:
Blake Kaplan 2010-07-19 13:36:49 -07:00
parent 9870b95ead
commit de74d9d8f4
23 changed files with 304 additions and 50 deletions

View File

@ -61,7 +61,7 @@ bool SendSyncMessageToParent(void* aCallbackData,
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
asyncMessages.SwapElements(tabChild->mASyncMessages);
PRUint32 len = asyncMessages.Length();
for (PRInt32 i = 0; i < len; ++i) {
for (PRUint32 i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run();
}
@ -286,8 +286,9 @@ nsInProcessTabChildGlobal::InitTabChildGlobal()
nsresult rv =
xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports,
NS_GET_IID(nsISupports), flags,
getter_AddRefs(mGlobal));
NS_GET_IID(nsISupports),
GetPrincipal(), EmptyCString(),
flags, getter_AddRefs(mGlobal));
NS_ENSURE_SUCCESS(rv, false);
JSObject* global = nsnull;

View File

@ -1302,7 +1302,10 @@ nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptCont
aScriptContext->SetGCOnDestruction(PR_FALSE);
}
aScriptContext->CreateOuterObject(this);
nsCOMPtr<nsIPrincipal> principal =
do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
aScriptContext->CreateOuterObject(this, principal);
aScriptContext->DidInitializeContext();
mJSObject = (JSObject *)aScriptContext->GetNativeGlobal();
}
@ -1617,6 +1620,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
Thaw();
}
// XXX Brain transplant outer window JSObject and create new one!
NS_ASSERTION(!GetCurrentInnerWindow() ||
GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
"Uh, mDocument doesn't match the current inner window "
@ -1815,6 +1820,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
void *&newGlobal = (void *&)newInnerWindow->mJSObject;
nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
aDocument->NodePrincipal(),
&newGlobal,
getter_AddRefs(holder));
NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,

View File

@ -72,10 +72,10 @@ public:
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
NS_ISCRIPTCONTEXTPRINCIPAL_IID)
// 5a5d683e-f387-4694-9ff0-3a90b3e6749e
// 5b6d04a3-f095-4924-ad84-4f44f9b3fae0
#define NS_ISCRIPTCONTEXT_IID \
{ 0x5a5d683e, 0xf387, 0x4694, \
{ 0x9f, 0xf0, 0x3a, 0x90, 0xb3, 0xe6, 0x74, 0x9e } }
{ 0x5b6d04a3, 0xf095, 0x4924, \
{ 0xad, 0x84, 0x4f, 0x44, 0xf9, 0xb3, 0xfa, 0xe0 } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */
@ -320,6 +320,7 @@ public:
virtual nsresult CreateNativeGlobalForInner(
nsIScriptGlobalObject *aNewInner,
PRBool aIsChrome,
nsIPrincipal *aPrincipal,
void **aNativeGlobal,
nsISupports **aHolder) = 0;
@ -342,7 +343,8 @@ public:
*
* @param aGlobalObject The script global object to use as our global.
*/
virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject) = 0;
virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
nsIPrincipal *aPrincipal) = 0;
/**
* Prepares this context for use with the current inner window for the

View File

@ -1590,6 +1590,13 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
JSAutoRequest ar(mContext);
nsJSVersionSetter setVersion(mContext, aVersion);
JSAutoCrossCompartmentCall accc;
if (!accc.enter(mContext, (JSObject *)aScopeObject)) {
JSPRINCIPALS_DROP(mContext, jsprin);
stack->Pop(nsnull);
return NS_ERROR_FAILURE;
}
++mExecuteDepth;
ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
@ -1777,6 +1784,13 @@ nsJSContext::EvaluateString(const nsAString& aScript,
// check it isn't JSVERSION_UNKNOWN.
if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
JSAutoRequest ar(mContext);
JSAutoCrossCompartmentCall accc;
if (!accc.enter(mContext, (JSObject *)aScopeObject)) {
stack->Pop(nsnull);
JSPRINCIPALS_DROP(mContext, jsprin);
return NS_ERROR_FAILURE;
}
nsJSVersionSetter setVersion(mContext, aVersion);
ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
@ -2202,6 +2216,12 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
jsval funval = OBJECT_TO_JSVAL(static_cast<JSObject *>(aHandler));
JSAutoRequest ar(mContext);
JSAutoCrossCompartmentCall accc;
if (!accc.enter(mContext, target)) {
stack->Pop(nsnull);
return NS_ERROR_FAILURE;
}
++mExecuteDepth;
PRBool ok = ::JS_CallFunctionValue(mContext, target,
funval, argc, argv, &rval);
@ -2517,6 +2537,7 @@ nsresult
nsJSContext::CreateNativeGlobalForInner(
nsIScriptGlobalObject *aNewInner,
PRBool aIsChrome,
nsIPrincipal *aPrincipal,
void **aNativeGlobal, nsISupports **aHolder)
{
nsIXPConnect *xpc = nsContentUtils::XPConnect();
@ -2525,6 +2546,7 @@ nsJSContext::CreateNativeGlobalForInner(
nsresult rv = xpc->
InitClassesWithNewWrappedGlobal(mContext,
aNewInner, NS_GET_IID(nsISupports),
aPrincipal, EmptyCString(),
flags,
getter_AddRefs(jsholder));
if (NS_FAILED(rv))
@ -2605,7 +2627,8 @@ nsJSContext::InitContext()
}
nsresult
nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject)
nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
nsIPrincipal *aPrincipal)
{
NS_PRECONDITION(!JS_GetGlobalObject(mContext),
"Outer window already initialized");
@ -2631,6 +2654,7 @@ nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject)
nsresult rv =
xpc->InitClassesWithNewWrappedGlobal(mContext, aGlobalObject,
NS_GET_IID(nsISupports),
aPrincipal, EmptyCString(),
flags, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -135,12 +135,14 @@ public:
virtual nsresult CreateNativeGlobalForInner(
nsIScriptGlobalObject *aGlobal,
PRBool aIsChrome,
nsIPrincipal *aPrincipal,
void **aNativeGlobal,
nsISupports **aHolder);
virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner,
void *aOuterGlobal);
virtual nsresult InitContext();
virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject);
virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
nsIPrincipal *aPrincipal);
virtual nsresult InitOuterWindow();
virtual PRBool IsContextInitialized();
virtual void FinalizeContext();

View File

@ -993,8 +993,9 @@ TabChild::InitTabChildGlobal()
nsresult rv =
xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports,
NS_GET_IID(nsISupports), flags,
getter_AddRefs(mRootGlobal));
NS_GET_IID(nsISupports),
scope->GetPrincipal(), EmptyCString(),
flags, getter_AddRefs(mRootGlobal));
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);

View File

@ -1611,10 +1611,14 @@ nsDOMWorker::CompileGlobalObject(JSContext* aCx)
const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
nsIXPConnect::OMIT_COMPONENTS_OBJECT;
nsCAutoString origin("DOM worker: ");
origin.AppendInt((PRUint64)this);
nsCOMPtr<nsIXPConnectJSObjectHolder> globalWrapper;
nsresult rv =
xpc->InitClassesWithNewWrappedGlobal(aCx, scopeSupports,
NS_GET_IID(nsISupports), flags,
NS_GET_IID(nsISupports), nsnull,
origin, flags,
getter_AddRefs(globalWrapper));
NS_ENSURE_SUCCESS(rv, PR_FALSE);

View File

@ -270,7 +270,7 @@ GetLine(char *bufp,
const char *prompt)
{
char line[256];
fprintf(stdout, prompt);
fputs(prompt, stdout);
fflush(stdout);
if (!fgets(line, sizeof line, file))
return JS_FALSE;
@ -1171,6 +1171,8 @@ XPCShellEnvironment::Init()
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
NS_GET_IID(nsISupports),
principal,
EmptyCString(),
nsIXPConnect::
FLAG_SYSTEM_GLOBAL_OBJECT,
getter_AddRefs(holder));

View File

@ -1081,6 +1081,14 @@ JS_GetImplementationVersion(void)
return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
}
JS_PUBLIC_API(JSCompartmentCallback)
JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
{
JSCompartmentCallback old = rt->compartmentCallback;
rt->compartmentCallback = callback;
return old;
}
JS_PUBLIC_API(JSWrapObjectCallback)
JS_SetWrapObjectCallback(JSContext *cx, JSWrapObjectCallback callback)
{
@ -1115,6 +1123,50 @@ JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
delete realcall;
}
bool
JSAutoCrossCompartmentCall::enter(JSContext *cx, JSObject *target)
{
JS_ASSERT(!call);
if (cx->compartment == target->getCompartment(cx))
return true;
call = JS_EnterCrossCompartmentCall(cx, target);
return call != NULL;
}
JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx,
JSCompartment *newCompartment)
: cx(cx), compartment(cx->compartment)
{
cx->compartment = newCompartment;
}
JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx, JSObject *target)
: cx(cx), compartment(cx->compartment)
{
cx->compartment = target->getCompartment(cx);
}
JSAutoEnterCompartment::~JSAutoEnterCompartment()
{
cx->compartment = compartment;
}
JS_PUBLIC_API(void *)
JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
{
CHECK_REQUEST(cx);
void *old = compartment->data;
compartment->data = data;
return old;
}
JS_PUBLIC_API(void *)
JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
{
CHECK_REQUEST(cx);
return compartment->data;
}
JS_PUBLIC_API(JSObject *)
JS_GetGlobalObject(JSContext *cx)
{

View File

@ -937,6 +937,9 @@ JS_ToggleOptions(JSContext *cx, uint32 options);
extern JS_PUBLIC_API(const char *)
JS_GetImplementationVersion(void);
extern JS_PUBLIC_API(JSCompartmentCallback)
JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback);
extern JS_PUBLIC_API(JSWrapObjectCallback)
JS_SetWrapObjectCallback(JSContext *cx, JSWrapObjectCallback callback);
@ -946,20 +949,22 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target);
extern JS_PUBLIC_API(void)
JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call);
extern JS_PUBLIC_API(void *)
JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data);
extern JS_PUBLIC_API(void *)
JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment);
#ifdef __cplusplus
JS_END_EXTERN_C
class JSAutoCrossCompartmentCall
class JS_PUBLIC_API(JSAutoCrossCompartmentCall)
{
JSCrossCompartmentCall *call;
public:
JSAutoCrossCompartmentCall() : call(NULL) {}
bool enter(JSContext *cx, JSObject *target) {
JS_ASSERT(!call);
call = JS_EnterCrossCompartmentCall(cx, target);
return call != NULL;
}
bool enter(JSContext *cx, JSObject *target);
~JSAutoCrossCompartmentCall() {
if (call)
@ -967,6 +972,16 @@ class JSAutoCrossCompartmentCall
}
};
class JS_FRIEND_API(JSAutoEnterCompartment)
{
JSContext *cx;
JSCompartment *compartment;
public:
JSAutoEnterCompartment(JSContext *cx, JSCompartment *newCompartment);
JSAutoEnterCompartment(JSContext *cx, JSObject *target);
~JSAutoEnterCompartment();
};
JS_BEGIN_EXTERN_C
#endif

View File

@ -1183,6 +1183,7 @@ class AutoIdVector;
struct JSCompartment {
JSRuntime *rt;
JSPrincipals *principals;
void *data;
bool marked;
js::WrapperMap crossCompartmentWrappers;
@ -1220,6 +1221,9 @@ struct JSRuntime {
/* Context create/destroy callback. */
JSContextCallback cxCallback;
/* Compartment create/destroy callback. */
JSCompartmentCallback compartmentCallback;
/*
* Shape regenerated whenever a prototype implicated by an "add property"
* property cache fill and induced trace guard has a readonly property or a

View File

@ -2967,6 +2967,7 @@ static void
SweepCompartments(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
JSCompartmentCallback callback = rt->compartmentCallback;
JSCompartment **read = rt->compartments.begin();
JSCompartment **end = rt->compartments.end();
JSCompartment **write = read;
@ -2978,6 +2979,8 @@ SweepCompartments(JSContext *cx)
/* Remove dead wrappers from the compartment map. */
compartment->sweep(cx);
} else {
if (callback)
(void) callback(cx, compartment, JSCOMPARTMENT_DESTROY);
if (compartment->principals)
JSPRINCIPALS_DROP(cx, compartment->principals);
delete compartment;
@ -3568,7 +3571,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
JSCompartment *compartment = new JSCompartment(rt);
if (!compartment || !compartment->init()) {
JS_ReportOutOfMemory(cx);
return false;
return NULL;
}
if (principals) {
@ -3576,12 +3579,21 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
JSPRINCIPALS_HOLD(cx, principals);
}
AutoLockGC lock(rt);
{
AutoLockGC lock(rt);
if (!rt->compartments.append(compartment)) {
AutoUnlockGC unlock(rt);
JS_ReportOutOfMemory(cx);
return false;
if (!rt->compartments.append(compartment)) {
AutoUnlockGC unlock(rt);
JS_ReportOutOfMemory(cx);
return NULL;
}
}
JSCompartmentCallback callback = rt->compartmentCallback;
if (callback && !callback(cx, compartment, JSCOMPARTMENT_NEW)) {
AutoLockGC lock(rt);
rt->compartments.popBack();
return NULL;
}
return compartment;

View File

@ -594,6 +594,14 @@ typedef JSBool
typedef JSObject *
(* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, uintN flags);
typedef enum {
JSCOMPARTMENT_NEW, /* XXX Does it make sense to have a NEW? */
JSCOMPARTMENT_DESTROY
} JSCompartmentOp;
typedef JSBool
(* JSCompartmentCallback)(JSContext *cx, JSCompartment *compartment, uintN compartmentOp);
JS_END_EXTERN_C
#endif /* jspubtd_h___ */

View File

@ -289,7 +289,7 @@ TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, u
}
JSCompartment::JSCompartment(JSRuntime *rt)
: rt(rt), principals(NULL), marked(false)
: rt(rt), principals(NULL), data(NULL), marked(false)
{
}

View File

@ -144,7 +144,7 @@ class JSCrossCompartmentWrapper : public JSWrapper {
namespace js {
class AutoCompartment
class JS_FRIEND_API(AutoCompartment)
{
public:
JSContext * const context;

View File

@ -397,7 +397,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
%}
[uuid(c53c54ac-afc1-458a-98f5-cadb52574e40)]
[uuid(68090BF7-EA5A-4C9E-BAF9-DB7AF857AC09)]
interface nsIXPConnect : nsISupports
{
%{ C++
@ -427,12 +427,27 @@ interface nsIXPConnect : nsISupports
* below). If you do not pass INIT_JS_STANDARD_CLASSES, then aCOMObj
* must implement nsIXPCScriptable so it can resolve the standard
* classes when asked by the JS engine.
*
* @param aJSContext the context to use while creating the global object.
* @param aCOMObj the native object that represents the global object.
* @param aIID the IID used to wrap the global object.
* @param aPrincipal the principal of the code that will run in this
* compartment. Can be null. If no specific origin is
* passed, will be used to compute the origin.
* @param aOrigin must be passed if aPrincipal is null. If non-empty,
* overrides aPrincipal's origin. (can be used to separate
* code from the same principals into different
* comartments, like sandboxes).
* @param aFlags one of the flags below specifying what options this
* global object wants.
*/
nsIXPConnectJSObjectHolder
initClassesWithNewWrappedGlobal(
in JSContextPtr aJSContext,
in nsISupports aCOMObj,
in nsIIDRef aIID,
in nsIPrincipal aPrincipal,
in ACString aOrigin,
in PRUint32 aFlags);
const PRUint32 INIT_JS_STANDARD_CLASSES = 1 << 0;

View File

@ -1208,6 +1208,8 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
NS_GET_IID(nsISupports),
mSystemPrincipal,
EmptyCString(),
nsIXPConnect::
FLAG_SYSTEM_GLOBAL_OBJECT,
getter_AddRefs(holder));

View File

@ -1867,25 +1867,26 @@ main(int argc, char **argv)
xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
#ifndef XPCONNECT_STANDALONE
nsCOMPtr<nsIPrincipal> systemprincipal;
// Fetch the system principal and store it away in a global, to use for
// script compilation in Load() and ProcessFile() (including interactive
// eval loop)
{
nsCOMPtr<nsIPrincipal> princ;
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && securityManager) {
rv = securityManager->GetSystemPrincipal(getter_AddRefs(princ));
rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal));
if (NS_FAILED(rv)) {
fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
} else {
// fetch the JS principals and stick in a global
rv = princ->GetJSPrincipals(cx, &gJSPrincipals);
rv = systemprincipal->GetJSPrincipals(cx, &gJSPrincipals);
if (NS_FAILED(rv)) {
fprintf(gErrFile, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
}
secman->SetSystemPrincipal(princ);
secman->SetSystemPrincipal(systemprincipal);
}
} else {
fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals");
@ -1921,6 +1922,8 @@ main(int argc, char **argv)
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
NS_GET_IID(nsISupports),
systemprincipal,
EmptyCString(),
nsIXPConnect::
FLAG_SYSTEM_GLOBAL_OBJECT,
getter_AddRefs(holder));

View File

@ -1102,17 +1102,60 @@ static JSClass xpcTempGlobalClass = {
JSCLASS_NO_OPTIONAL_MEMBERS
};
nsresult
xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
const nsACString &origin, nsIPrincipal *principal,
JSObject **global, JSCompartment **compartment)
{
XPCCompartmentMap& map = nsXPConnect::GetRuntimeInstance()->GetCompartmentMap();
JSObject *tempGlobal;
if(!map.Get(origin, compartment))
{
JSPrincipals *principals = nsnull;
if(principal)
principal->GetJSPrincipals(cx, &principals);
tempGlobal = JS_NewCompartmentAndGlobalObject(cx, clasp, principals);
if(principals)
JSPRINCIPALS_DROP(cx, principals);
if(!tempGlobal)
return UnexpectedFailure(NS_ERROR_FAILURE);
JSAutoEnterCompartment autocompartment(cx, tempGlobal);
*global = tempGlobal;
*compartment = tempGlobal->getCompartment(cx);
JS_SetCompartmentPrivate(cx, *compartment, ToNewCString(origin));
map.Put(origin, *compartment);
}
else
{
JSAutoEnterCompartment autocompartment(cx, *compartment);
tempGlobal = JS_NewGlobalObject(cx, clasp);
if(!tempGlobal)
return UnexpectedFailure(NS_ERROR_FAILURE);
*global = tempGlobal;
}
return NS_OK;
}
/* nsIXPConnectJSObjectHolder initClassesWithNewWrappedGlobal (in JSContextPtr aJSContext, in nsISupports aCOMObj, in nsIIDRef aIID, in PRUint32 aFlags); */
NS_IMETHODIMP
nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
nsISupports *aCOMObj,
const nsIID & aIID,
nsIPrincipal * aPrincipal,
const nsACString & aOrigin,
PRUint32 aFlags,
nsIXPConnectJSObjectHolder **_retval)
{
NS_ASSERTION(aJSContext, "bad param");
NS_ASSERTION(aCOMObj, "bad param");
NS_ASSERTION(_retval, "bad param");
NS_ASSERTION(!aOrigin.IsEmpty() || aPrincipal, "must be able to assign an origin");
// XXX This is not pretty. We make a temporary global object and
// init it with all the Components object junk just so we have a
@ -1121,13 +1164,25 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
PRBool system = (aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT) != 0;
JSObject* tempGlobal = JS_NewGlobalObject(aJSContext, &xpcTempGlobalClass);
nsCString origin;
if(aOrigin.IsEmpty())
aPrincipal->GetOrigin(getter_Copies(origin));
else
origin = aOrigin;
if(!tempGlobal ||
(system && !JS_MakeSystemObject(aJSContext, tempGlobal)) ||
!JS_SetParent(aJSContext, tempGlobal, nsnull) ||
!JS_SetPrototype(aJSContext, tempGlobal, nsnull))
SaveFrame sf(ccx);
JSCompartment* compartment;
JSObject* tempGlobal;
nsresult rv = xpc_CreateGlobalObject(ccx, &xpcTempGlobalClass, origin,
aPrincipal, &tempGlobal, &compartment);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoEnterCompartment autocompartment(ccx, compartment);
PRBool system = (aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT) != 0;
if(system && !JS_MakeSystemObject(aJSContext, tempGlobal))
return UnexpectedFailure(NS_ERROR_FAILURE);
jsval v;
@ -1140,7 +1195,6 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
if(NS_FAILED(InitClasses(aJSContext, tempGlobal)))
return UnexpectedFailure(NS_ERROR_FAILURE);
nsresult rv;
if(!XPCConvert::NativeInterface2JSObject(ccx, &v,
getter_AddRefs(holder),
aCOMObj, &aIID, nsnull,
@ -1193,7 +1247,6 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
if(!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
// XPCCallContext gives us an active request needed to save/restore.
SaveFrame sf(ccx);
if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, globalJSObj))
return UnexpectedFailure(NS_ERROR_FAILURE);

View File

@ -3242,15 +3242,20 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop)
return NS_ERROR_OUT_OF_MEMORY;
}
JSPrincipals *jsPrincipals;
rv = sop->GetPrincipal()->GetJSPrincipals(cx, &jsPrincipals);
if (NS_FAILED(rv))
return rv;
JSObject *sandbox = JS_NewCompartmentAndGlobalObject(cx, &SandboxClass, jsPrincipals);
if (jsPrincipals)
JSPRINCIPALS_DROP(cx, jsPrincipals);
if (!sandbox)
return NS_ERROR_XPC_UNEXPECTED;
nsIPrincipal *principal = sop->GetPrincipal();
nsAdoptingCString principalorigin;
principal->GetOrigin(getter_Copies(principalorigin));
nsCAutoString origin("sandbox:");
origin.Append(principalorigin);
JSCompartment *compartment;
JSObject *sandbox;
rv = xpc_CreateGlobalObject(cx, &SandboxClass, origin, principal, &sandbox,
&compartment);
NS_ENSURE_SUCCESS(rv, rv);
js::AutoObjectRooter tvr(cx, sandbox);
{

View File

@ -243,6 +243,32 @@ ContextCallback(JSContext *cx, uintN operation)
return JS_TRUE;
}
static JSBool
CompartmentCallback(JSContext *cx, JSCompartment *compartment, uintN op)
{
if(op == JSCOMPARTMENT_NEW)
return JS_TRUE;
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
if(!self)
return JS_TRUE;
XPCCompartmentMap& map = self->GetCompartmentMap();
nsAdoptingCString origin;
origin.Adopt(static_cast<char *>(JS_SetCompartmentPrivate(cx, compartment, nsnull)));
#ifdef DEBUG
{
JSCompartment *current;
NS_ASSERTION(map.Get(origin, &current), "no compartment?");
NS_ASSERTION(current == compartment, "compartment mismatch");
}
#endif
map.Remove(origin);
return JS_TRUE;
}
struct ObjectHolder : public JSDHashEntryHdr
{
void *holder;
@ -1092,6 +1118,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
// the GC's allocator.
JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
JS_SetContextCallback(mJSRuntime, ContextCallback);
JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback);
JS_SetGCCallbackRT(mJSRuntime, GCCallback);
JS_SetExtraGCRoots(mJSRuntime, TraceJS, this);
mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
@ -1105,6 +1132,8 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
sizeof(ObjectHolder), 512))
mJSHolders.ops = nsnull;
mCompartmentMap.Init();
// Install a JavaScript 'debugger' keyword handler in debug builds only
#ifdef DEBUG
if(mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)

View File

@ -95,6 +95,7 @@
#include "nsXPIDLString.h"
#include "nsAutoJSValHolder.h"
#include "mozilla/AutoRestore.h"
#include "nsDataHashtable.h"
#include "nsThreadUtils.h"
#include "nsIJSContextStack.h"
@ -243,6 +244,8 @@ extern const char XPC_SCRIPT_ERROR_CONTRACTID[];
extern const char XPC_ID_CONTRACTID[];
extern const char XPC_XPCONNECT_CONTRACTID[];
typedef nsDataHashtableMT<nsCStringHashKey, JSCompartment *> XPCCompartmentMap;
/***************************************************************************/
// useful macros...
@ -623,6 +626,9 @@ public:
XPCNativeWrapperMap* GetExplicitNativeWrapperMap() const
{return mExplicitNativeWrapperMap;}
XPCCompartmentMap& GetCompartmentMap()
{return mCompartmentMap;}
XPCLock* GetMapLock() const {return mMapLock;}
JSBool OnJSContextNew(JSContext* cx);
@ -741,6 +747,7 @@ private:
XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap;
XPCNativeWrapperMap* mExplicitNativeWrapperMap;
XPCCompartmentMap mCompartmentMap;
XPCLock* mMapLock;
PRThread* mThreadRunningGC;
nsTArray<nsXPCWrappedJS*> mWrappedJSToReleaseArray;
@ -3778,6 +3785,11 @@ xpc_DumpJSObject(JSObject* obj);
extern JSBool
xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt);
nsresult
xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
const nsACString &origin, nsIPrincipal *principal,
JSObject **global, JSCompartment **compartment);
/***************************************************************************/
// Definition of nsScriptError, defined here because we lack a place to put

View File

@ -1308,6 +1308,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
obj = thisObj = wrapper->GetJSObject();
JSAutoEnterCompartment autoCompartment(ccx, obj);
// XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
paramCount = info->num_args;
argc = paramCount -