Be more careful pushing/popping contexts. b=352264 r=jst sr=bzbarsky/jst

This commit is contained in:
dbaron%dbaron.org 2006-09-12 22:58:11 +00:00
parent 2964cc44d3
commit bb32a15350
11 changed files with 103 additions and 105 deletions

View File

@ -1730,7 +1730,10 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
// in the same scope as aTarget.
rv = ConvertSupportsTojsvals(aargv, target, &argc,
NS_REINTERPRET_CAST(void **, &argv), &mark);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
stack->Pop(nsnull);
return rv;
}
AutoFreeJSStack stackGuard(mContext, mark); // ensure always freed.

View File

@ -358,23 +358,20 @@ MozAxAutoPushJSContext::MozAxAutoPushJSContext(JSContext *cx,
nsIURI * aURI)
: mContext(cx), mPushResult(NS_OK)
{
mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
nsCOMPtr<nsIJSContextStack> contextStack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if(mContextStack)
JSContext* currentCX;
if(contextStack &&
// Don't push if the current context is already on the stack.
(NS_FAILED(contextStack->Peek(&currentCX)) ||
cx != currentCX) )
{
JSContext* currentCX;
if(NS_SUCCEEDED(mContextStack->Peek(&currentCX)))
if (NS_SUCCEEDED(contextStack->Push(cx)))
{
// Is the current context already on the stack?
if(cx == currentCX)
mContextStack = nsnull;
else
{
mContextStack->Push(cx);
// Leave the reference to the mContextStack to
// indicate that we need to pop it in our dtor.
}
// Leave the reference in mContextStack to
// indicate that we need to pop it in our dtor.
mContextStack.swap(contextStack);
}
}

View File

@ -296,26 +296,22 @@ JSContextAutoPopper::~JSContextAutoPopper()
nsresult JSContextAutoPopper::Push(JSContext *cx)
{
nsresult rv = NS_OK;
if (mContext) // only once
return NS_ERROR_FAILURE;
mService = do_GetService(sJSStackContractID);
if(mService) {
if (cx) {
mContext = cx;
} else {
rv = mService->GetSafeJSContext(&mContext);
// Get the safe context if we're not provided one.
if (!cx && NS_FAILED(mService->GetSafeJSContext(&cx))) {
cx = nsnull;
}
if (NS_SUCCEEDED(rv) && mContext) {
rv = mService->Push(mContext);
if (NS_FAILED(rv))
mContext = 0;
// Save cx in mContext to indicate need to pop.
if (cx && NS_SUCCEEDED(mService->Push(cx))) {
mContext = cx;
}
}
return mContext ? NS_OK : NS_ERROR_FAILURE;
return mContext ? NS_OK : NS_ERROR_FAILURE;
}
/****************************************************************

View File

@ -110,22 +110,20 @@ AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports,
JSContext *cx)
: mContext(cx), mPushResult(NS_OK)
{
mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
nsCOMPtr<nsIJSContextStack> contextStack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if(mContextStack)
JSContext* currentCX;
if(contextStack &&
// Don't push if the current context is already on the stack.
(NS_FAILED(contextStack->Peek(&currentCX)) ||
cx != currentCX) )
{
JSContext* currentCX;
if(NS_SUCCEEDED(mContextStack->Peek(&currentCX)))
if (NS_SUCCEEDED(contextStack->Push(cx)))
{
// Is the current context already on the stack?
if(cx == currentCX)
mContextStack = nsnull;
else
{
mContextStack->Push(cx);
// Leave the reference to the mContextStack to
// indicate that we need to pop it in our dtor.
}
// Leave the reference in mContextStack to
// indicate that we need to pop it in our dtor.
mContextStack.swap(contextStack);
}
}

View File

@ -299,25 +299,6 @@ XPCCallContext::~XPCCallContext()
{
mXPCContext->SetCallingLangType(mPrevCallerLanguage);
if(mContextPopRequired)
{
XPCJSContextStack* stack = mThreadData->GetJSContextStack();
if(stack)
{
#ifdef DEBUG
JSContext* poppedCX;
nsresult rv = stack->Pop(&poppedCX);
NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == mJSContext, "bad pop");
#else
(void) stack->Pop(nsnull);
#endif
}
else
{
NS_ASSERTION(0, "bad!");
}
}
#ifdef DEBUG
XPCCallContext* old = mThreadData->SetCallContext(mPrevCallContext);
NS_ASSERTION(old == this, "bad pop from per thread data");
@ -326,6 +307,22 @@ XPCCallContext::~XPCCallContext()
#endif
}
if(mContextPopRequired)
{
XPCJSContextStack* stack = mThreadData->GetJSContextStack();
NS_ASSERTION(stack, "bad!");
if(stack)
{
#ifdef DEBUG
JSContext* poppedCX;
nsresult rv = stack->Pop(&poppedCX);
NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == mJSContext, "bad pop");
#else
(void) stack->Pop(nsnull);
#endif
}
}
if(mJSContext)
{
if(mCallerLanguage == NATIVE_CALLER && JS_GetContextThread(mJSContext))

View File

@ -1999,12 +1999,14 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
NPBool bPushCaller = (result != nsnull);
if (bPushCaller) {
rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIPluginInstancePeer> peer;
if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
nsCOMPtr<nsIPluginInstancePeer2> peer2 =
do_QueryInterface(peer, &rv);
do_QueryInterface(peer);
if (NS_SUCCEEDED(rv) && peer2) {
if (peer2) {
JSContext *cx;
rv = peer2->GetJSContext(&cx);

View File

@ -78,22 +78,6 @@ static JSRuntime *sJSRuntime;
// while executing JS on the context.
static nsIJSContextStack *sContextStack;
class AutoCXPusher
{
public:
AutoCXPusher(JSContext *cx)
{
if (sContextStack)
sContextStack->Push(cx);
}
~AutoCXPusher()
{
if (sContextStack)
sContextStack->Pop(nsnull);
}
};
NPClass nsJSObjWrapper::sJSObjWrapperNPClass =
{
NP_CLASS_STRUCT_VERSION,
@ -230,6 +214,31 @@ OnWrapperDestroyed()
}
}
struct AutoCXPusher
{
AutoCXPusher(JSContext *cx)
{
// Precondition explaining why we don't need to worry about errors
// in OnWrapperCreated.
NS_PRECONDITION(sWrapperCount > 0,
"must have live wrappers when using AutoCXPusher");
// Call OnWrapperCreated and OnWrapperDestroyed to ensure that the
// last OnWrapperDestroyed doesn't happen while we're on the stack
// and null out sContextStack.
OnWrapperCreated();
sContextStack->Push(cx);
}
~AutoCXPusher()
{
sContextStack->Pop(nsnull);
OnWrapperDestroyed();
}
};
static JSContext *
GetJSContext(NPP npp)
{

View File

@ -1656,18 +1656,17 @@ SafeJSContext::~SafeJSContext() {
}
nsresult SafeJSContext::Push() {
nsresult rv;
if (mContext) // only once
return NS_ERROR_FAILURE;
mService = do_GetService(sJSStackContractID);
if(mService) {
rv = mService->GetSafeJSContext(&mContext);
if (NS_SUCCEEDED(rv) && mContext) {
rv = mService->Push(mContext);
if (NS_FAILED(rv))
mContext = 0;
JSContext *cx;
if (NS_SUCCEEDED(mService->GetSafeJSContext(&cx)) &&
cx &&
NS_SUCCEEDED(mService->Push(cx))) {
// Save cx in mContext to indicate need to pop.
mContext = cx;
}
}
return mContext ? NS_OK : NS_ERROR_FAILURE;

View File

@ -1512,18 +1512,17 @@ SafeJSContext::~SafeJSContext() {
}
nsresult SafeJSContext::Push() {
nsresult rv;
if (mContext) // only once
return NS_ERROR_FAILURE;
mService = do_GetService(sJSStackContractID);
if(mService) {
rv = mService->GetSafeJSContext(&mContext);
if (NS_SUCCEEDED(rv) && mContext) {
rv = mService->Push(mContext);
if (NS_FAILED(rv))
mContext = 0;
JSContext *cx;
if (NS_SUCCEEDED(mService->GetSafeJSContext(&cx)) &&
cx &&
NS_SUCCEEDED(mService->Push(cx))) {
// Save cx in mContext to indicate need to pop.
mContext = cx;
}
}
return mContext ? NS_OK : NS_ERROR_FAILURE;

View File

@ -2300,21 +2300,20 @@ SafeJSContext::~SafeJSContext() {
}
nsresult SafeJSContext::Push() {
nsresult rv;
if (mContext) // only once
return NS_ERROR_FAILURE;
mService = do_GetService(sJSStackContractID);
if(mService) {
rv = mService->GetSafeJSContext(&mContext);
if (NS_SUCCEEDED(rv) && mContext) {
rv = mService->Push(mContext);
if (NS_FAILED(rv))
mContext = 0;
JSContext *cx;
if (NS_SUCCEEDED(mService->GetSafeJSContext(&cx)) &&
cx &&
NS_SUCCEEDED(mService->Push(cx))) {
// Save cx in mContext to indicate need to pop.
mContext = cx;
}
}
return mContext ? NS_OK : NS_ERROR_FAILURE;
return mContext ? NS_OK : NS_ERROR_FAILURE;
}

View File

@ -2314,18 +2314,17 @@ SafeJSContext::~SafeJSContext() {
}
nsresult SafeJSContext::Push() {
nsresult rv;
if (mContext) // only once
return NS_ERROR_FAILURE;
mService = do_GetService(sJSStackContractID);
if(mService) {
rv = mService->GetSafeJSContext(&mContext);
if (NS_SUCCEEDED(rv) && mContext) {
rv = mService->Push(mContext);
if (NS_FAILED(rv))
mContext = 0;
JSContext *cx;
if (NS_SUCCEEDED(mService->GetSafeJSContext(&cx)) &&
cx &&
NS_SUCCEEDED(mService->Push(cx))) {
// Save cx in mContext to indicate need to pop.
mContext = cx;
}
}
return mContext ? NS_OK : NS_ERROR_FAILURE;