Bug 593742 - nsDOMWorker has to set the right compartment. r=bent.

--HG--
extra : rebase_source : 1f309d333686fdad21a7b6940873994ccc64157d
This commit is contained in:
Jason Orendorff 2010-09-09 11:13:06 -05:00
Родитель 1773e67db8
Коммит 04c9fcd6a0
4 изменённых файлов: 91 добавлений и 32 удалений

Просмотреть файл

@ -395,35 +395,41 @@ public:
JS_TriggerOperationCallback(cx);
PRBool killWorkerWhenDone;
{
nsLazyAutoRequest ar;
JSAutoCrossCompartmentCall axcc;
// Tell the worker which context it will be using
if (mWorker->SetGlobalForContext(cx)) {
RunQueue(cx, &killWorkerWhenDone);
// Tell the worker which context it will be using
if (mWorker->SetGlobalForContext(cx, &ar, &axcc)) {
NS_ASSERTION(ar.entered(), "SetGlobalForContext must enter request on success");
NS_ASSERTION(axcc.entered(), "SetGlobalForContext must enter xcc on success");
// Code in XPConnect assumes that the context's global object won't be
// replaced outside of a request.
JSAutoRequest ar(cx);
RunQueue(cx, &killWorkerWhenDone);
// Remove the global object from the context so that it might be garbage
// collected.
JS_SetGlobalObject(cx, NULL);
JS_SetContextPrivate(cx, NULL);
}
else {
{
// Code in XPConnect assumes that the context's global object won't be
// replaced outside of a request.
JSAutoRequest ar(cx);
// This is usually due to a parse error in the worker script...
// Remove the global object from the context so that it might be garbage
// collected.
JS_SetGlobalObject(cx, NULL);
JS_SetContextPrivate(cx, NULL);
}
else {
NS_ASSERTION(!ar.entered(), "SetGlobalForContext must not enter request on failure");
NS_ASSERTION(!axcc.entered(), "SetGlobalForContext must not enter xcc on failure");
nsAutoMonitor mon(gDOMThreadService->mMonitor);
killWorkerWhenDone = mKillWorkerWhenDone;
gDOMThreadService->WorkerComplete(this);
mon.NotifyAll();
{
// Code in XPConnect assumes that the context's global object won't be
// replaced outside of a request.
JSAutoRequest ar2(cx);
// This is usually due to a parse error in the worker script...
JS_SetGlobalObject(cx, NULL);
JS_SetContextPrivate(cx, NULL);
}
nsAutoMonitor mon(gDOMThreadService->mMonitor);
killWorkerWhenDone = mKillWorkerWhenDone;
gDOMThreadService->WorkerComplete(this);
mon.NotifyAll();
}
}
if (killWorkerWhenDone) {

Просмотреть файл

@ -1560,26 +1560,41 @@ nsDOMWorker::PostMessageInternal(PRBool aToInner)
}
PRBool
nsDOMWorker::SetGlobalForContext(JSContext* aCx)
nsDOMWorker::SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest,
JSAutoCrossCompartmentCall *aCall)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (!CompileGlobalObject(aCx)) {
if (!CompileGlobalObject(aCx, aRequest, aCall)) {
return PR_FALSE;
}
JSAutoRequest ar(aCx);
JS_SetGlobalObject(aCx, mGlobal);
return PR_TRUE;
}
PRBool
nsDOMWorker::CompileGlobalObject(JSContext* aCx)
nsDOMWorker::CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest,
JSAutoCrossCompartmentCall *aCall)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
// On success, we enter a request and a cross-compartment call that both
// belong to the caller. But on failure, we must not remain in a request or
// cross-compartment call. So we enter both only locally at first. On
// failure, the local request and call will automatically get cleaned
// up. Once success is certain, we swap them into *aRequest and *aCall.
nsLazyAutoRequest localRequest;
JSAutoCrossCompartmentCall localCall;
localRequest.enter(aCx);
PRBool success;
if (mGlobal) {
success = localCall.enter(aCx, mGlobal);
NS_ENSURE_TRUE(success, PR_FALSE);
aRequest->swap(localRequest);
aCall->swap(localCall);
return PR_TRUE;
}
@ -1591,8 +1606,6 @@ nsDOMWorker::CompileGlobalObject(JSContext* aCx)
NS_ASSERTION(!mScriptURL.IsEmpty(), "Must have a url here!");
JSAutoRequest ar(aCx);
NS_ASSERTION(!JS_GetGlobalObject(aCx), "Global object should be unset!");
nsRefPtr<nsDOMWorkerScope> scope = new nsDOMWorkerScope(this);
@ -1622,6 +1635,9 @@ nsDOMWorker::CompileGlobalObject(JSContext* aCx)
NS_ASSERTION(JS_GetGlobalObject(aCx) == global, "Global object mismatch!");
success = localCall.enter(aCx, global);
NS_ENSURE_TRUE(success, PR_FALSE);
#ifdef DEBUG
{
jsval components;
@ -1633,7 +1649,7 @@ nsDOMWorker::CompileGlobalObject(JSContext* aCx)
#endif
// Set up worker thread functions.
PRBool success = JS_DefineFunctions(aCx, global, gDOMWorkerFunctions);
success = JS_DefineFunctions(aCx, global, gDOMWorkerFunctions);
NS_ENSURE_TRUE(success, PR_FALSE);
if (mPrivilegeModel == CHROME) {
@ -1690,6 +1706,8 @@ nsDOMWorker::CompileGlobalObject(JSContext* aCx)
NS_ASSERTION(mPrincipal && mURI, "Script loader didn't set our principal!");
aRequest->swap(localRequest);
aCall->swap(localCall);
return PR_TRUE;
}

Просмотреть файл

@ -105,6 +105,33 @@ private:
PRPackedBool mHasOnerror;
};
class nsLazyAutoRequest
{
public:
nsLazyAutoRequest() : mCx(nsnull) {}
~nsLazyAutoRequest() {
if (mCx)
JS_EndRequest(mCx);
}
void enter(JSContext *aCx) {
JS_BeginRequest(aCx);
mCx = aCx;
}
bool entered() const { return mCx != nsnull; }
void swap(nsLazyAutoRequest &other) {
JSContext *tmp = mCx;
mCx = other.mCx;
other.mCx = tmp;
}
private:
JSContext *mCx;
};
class nsDOMWorker : public nsDOMWorkerMessageHandler,
public nsIChromeWorker,
public nsITimerCallback,
@ -174,7 +201,7 @@ public:
PRBool IsClosing();
PRBool IsSuspended();
PRBool SetGlobalForContext(JSContext* aCx);
PRBool SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoCrossCompartmentCall *aCall);
void SetPool(nsDOMWorkerPool* aPool);
@ -258,7 +285,7 @@ private:
nsresult PostMessageInternal(PRBool aToInner);
PRBool CompileGlobalObject(JSContext* aCx);
PRBool CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoCrossCompartmentCall *aCall);
PRUint32 NextTimeoutId() {
return ++mNextTimeoutId;

Просмотреть файл

@ -968,10 +968,18 @@ class JS_PUBLIC_API(JSAutoCrossCompartmentCall)
bool enter(JSContext *cx, JSObject *target);
bool entered() const { return call != NULL; }
~JSAutoCrossCompartmentCall() {
if (call)
JS_LeaveCrossCompartmentCall(call);
}
void swap(JSAutoCrossCompartmentCall &other) {
JSCrossCompartmentCall *tmp = call;
call = other.call;
other.call = tmp;
}
};
class JS_FRIEND_API(JSAutoEnterCompartment)