зеркало из https://github.com/mozilla/pjs.git
Fixing bug 408009. Make doGetObjectPrincipal() faster. r+sr=bzbarsky@mit.edu, r+a=brendan@mozilla.org
This commit is contained in:
Родитель
a36f59651d
Коммит
d05eccb938
|
@ -409,8 +409,11 @@ private:
|
|||
// Returns null if a principal cannot be found; generally callers
|
||||
// should error out at that point.
|
||||
static nsIPrincipal*
|
||||
doGetObjectPrincipal(JSContext *cx, JSObject *obj,
|
||||
PRBool aAllowShortCircuit = PR_FALSE);
|
||||
doGetObjectPrincipal(JSContext *cx, JSObject *obj
|
||||
#ifdef DEBUG
|
||||
, PRBool aAllowShortCircuit = PR_TRUE
|
||||
#endif
|
||||
);
|
||||
|
||||
// Returns null if a principal cannot be found. Note that rv can be NS_OK
|
||||
// when this happens -- this means that there was no JS running.
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include "nsDOMError.h"
|
||||
#include "nsDOMCID.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsarena.h"
|
||||
#include "jsfun.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIXPCSecurityManager.h"
|
||||
#include "nsTextFormatter.h"
|
||||
|
@ -96,6 +98,14 @@ nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
|
|||
nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
|
||||
JSRuntime *nsScriptSecurityManager::sRuntime = 0;
|
||||
|
||||
// Info we need about the JSClasses used by XPConnects wrapped
|
||||
// natives, to avoid having to QI to nsIXPConnectWrappedNative all the
|
||||
// time when doing security checks.
|
||||
static const JSClass *sXPCWrappedNativeJSClass;
|
||||
static JSGetObjectOps sXPCWrappedNativeGetObjOps1;
|
||||
static JSGetObjectOps sXPCWrappedNativeGetObjOps2;
|
||||
|
||||
|
||||
///////////////////////////
|
||||
// Convenience Functions //
|
||||
///////////////////////////
|
||||
|
@ -2286,8 +2296,11 @@ nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
|
|||
|
||||
// static
|
||||
nsIPrincipal*
|
||||
nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj,
|
||||
PRBool aAllowShortCircuit)
|
||||
nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj
|
||||
#ifdef DEBUG
|
||||
, PRBool aAllowShortCircuit
|
||||
#endif
|
||||
)
|
||||
{
|
||||
NS_ASSERTION(aCx && aObj, "Bad call to doGetObjectPrincipal()!");
|
||||
nsIPrincipal* result = nsnull;
|
||||
|
@ -2296,58 +2309,125 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj,
|
|||
JSObject* origObj = aObj;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
const JSClass *jsClass = JS_GetClass(aCx, aObj);
|
||||
const JSClass *jsClass = JS_GET_CLASS(aCx, aObj);
|
||||
|
||||
if (jsClass && !(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_PRIVATE_IS_NSISUPPORTS)))
|
||||
{
|
||||
// No need to refcount |priv| here.
|
||||
nsISupports *priv = (nsISupports *)JS_GetPrivate(aCx, aObj);
|
||||
// A common case seen in this code is that we enter this function
|
||||
// with aObj being a Function object, whose parent is a Call
|
||||
// object. Neither of those have object principals, so we can skip
|
||||
// those objects here before we enter the below loop. That way we
|
||||
// avoid wasting time checking properties of their classes etc in
|
||||
// the loop.
|
||||
|
||||
/*
|
||||
* If it's a wrapped native (as most
|
||||
* JSCLASS_PRIVATE_IS_NSISUPPORTS objects are in mozilla),
|
||||
* check the underlying native instead.
|
||||
*/
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
|
||||
do_QueryInterface(priv);
|
||||
if (jsClass == &js_FunctionClass) {
|
||||
aObj = JS_GetParent(aCx, aObj);
|
||||
|
||||
if (NS_LIKELY(xpcWrapper != nsnull))
|
||||
{
|
||||
if (NS_UNLIKELY(aAllowShortCircuit))
|
||||
{
|
||||
result = xpcWrapper->GetObjectPrincipal();
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrin;
|
||||
objPrin = do_QueryWrappedNative(xpcWrapper);
|
||||
if (objPrin)
|
||||
{
|
||||
result = objPrin->GetPrincipal();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrin;
|
||||
objPrin = do_QueryInterface(priv);
|
||||
if (objPrin)
|
||||
{
|
||||
result = objPrin->GetPrincipal();
|
||||
if (!aObj)
|
||||
return nsnull;
|
||||
|
||||
jsClass = JS_GET_CLASS(aCx, aObj);
|
||||
|
||||
if (jsClass == &js_CallClass) {
|
||||
aObj = JS_GetParent(aCx, aObj);
|
||||
|
||||
if (!aObj)
|
||||
return nsnull;
|
||||
|
||||
jsClass = JS_GET_CLASS(aCx, aObj);
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
do {
|
||||
// Note: jsClass is set before this loop, and also at the
|
||||
// *end* of this loop.
|
||||
|
||||
// NOTE: These class and getObjectOps hook checks better match
|
||||
// what IS_WRAPPER_CLASS() does in xpconnect!
|
||||
if (jsClass == sXPCWrappedNativeJSClass ||
|
||||
jsClass->getObjectOps == sXPCWrappedNativeGetObjOps1 ||
|
||||
jsClass->getObjectOps == sXPCWrappedNativeGetObjOps2) {
|
||||
nsIXPConnectWrappedNative *xpcWrapper =
|
||||
(nsIXPConnectWrappedNative *)JS_GetPrivate(aCx, aObj);
|
||||
|
||||
if (xpcWrapper) {
|
||||
nsISupports *native = xpcWrapper->Native();
|
||||
char ch = jsClass->name[0];
|
||||
|
||||
// XXXjst: Ideally this code would simply call into
|
||||
// xpcWrapper->GetObjectPrincipal() and use that if we
|
||||
// find a principal through that. If not, we can fall
|
||||
// back to the below code. See bug 317240.
|
||||
|
||||
// For classes that are unlikely to be window object
|
||||
// classes (Window, ModalContentWindow, and
|
||||
// ChromeWindow), check if the native pointer is an
|
||||
// nsINode. Note that this is merely a performance
|
||||
// optimization, so missing this optimization is
|
||||
// non-critical and must result in us finding the same
|
||||
// principal that we would have gotten by asking the
|
||||
// nsINode here.
|
||||
if (ch != 'W' && ch != 'M' && ch != 'C'
|
||||
#ifdef DEBUG
|
||||
&& aAllowShortCircuit
|
||||
#endif
|
||||
) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(native);
|
||||
|
||||
if (node) {
|
||||
result = node->NodePrincipal();
|
||||
|
||||
// NodePrincipal() *always* returns a
|
||||
// principal.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, check if it points to an
|
||||
// nsIScriptObjectPrincipal
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
|
||||
do_QueryInterface(native);
|
||||
if (objPrin) {
|
||||
result = objPrin->GetPrincipal();
|
||||
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
|
||||
nsISupports *priv = (nsISupports *)JS_GetPrivate(aCx, aObj);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aAllowShortCircuit) {
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
|
||||
do_QueryInterface(priv);
|
||||
|
||||
NS_ASSERTION(!xpcWrapper,
|
||||
"Uh, an nsIXPConnectWrappedNative with the "
|
||||
"wrong JSClass or getObjectOps hooks!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
|
||||
do_QueryInterface(priv);
|
||||
|
||||
if (objPrin) {
|
||||
result = objPrin->GetPrincipal();
|
||||
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aObj = JS_GetParent(aCx, aObj);
|
||||
} while (aObj);
|
||||
|
||||
if (!aObj)
|
||||
break;
|
||||
|
||||
jsClass = JS_GET_CLASS(aCx, aObj);
|
||||
} while (1);
|
||||
|
||||
NS_ASSERTION(!aAllowShortCircuit ||
|
||||
result == doGetObjectPrincipal(aCx, origObj, PR_FALSE),
|
||||
|
@ -3232,6 +3312,10 @@ nsresult nsScriptSecurityManager::Init()
|
|||
#endif
|
||||
JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);
|
||||
|
||||
sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass,
|
||||
&sXPCWrappedNativeGetObjOps1,
|
||||
&sXPCWrappedNativeGetObjOps2);
|
||||
|
||||
// For now, assert that no callback was set previously
|
||||
NS_ASSERTION(!oldCallback, "Someone already set a JS CheckObjectAccess callback");
|
||||
return NS_OK;
|
||||
|
|
|
@ -102,7 +102,7 @@ struct JSFunction {
|
|||
: (fun)->nargs)
|
||||
|
||||
extern JSClass js_ArgumentsClass;
|
||||
extern JSClass js_CallClass;
|
||||
extern JS_FRIEND_DATA(JSClass) js_CallClass;
|
||||
|
||||
/* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */
|
||||
extern JS_FRIEND_DATA(JSClass) js_FunctionClass;
|
||||
|
|
|
@ -62,6 +62,8 @@
|
|||
[ptr] native JSObjectPtr(JSObject);
|
||||
[ptr] native JSValPtr(jsval);
|
||||
native JSVal(jsval);
|
||||
[ptr] native JSClassConstPtr(const JSClass);
|
||||
native JSGetObjectOps(JSGetObjectOps);
|
||||
native JSID(jsid);
|
||||
[ptr] native voidPtrPtr(void*);
|
||||
[ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
|
||||
|
@ -445,7 +447,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
|
|||
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
|
||||
%}
|
||||
|
||||
[uuid(9f45711b-bf4f-4af6-a71d-d165f042986d)]
|
||||
[uuid(256a41a5-10e6-40a1-8392-8baa4adfabe2)]
|
||||
interface nsIXPConnect : nsISupports
|
||||
{
|
||||
%{ C++
|
||||
|
@ -751,4 +753,14 @@ interface nsIXPConnect : nsISupports
|
|||
*/
|
||||
[noscript,notxpcom] void noteJSContext(in JSContextPtr aJSContext,
|
||||
in nsCCTraversalCallbackRef aCb);
|
||||
|
||||
/**
|
||||
* Get the JSClass and JSGetObjectOps pointers to use for
|
||||
* identifying JSObjects that hold nsIXPConnectWrappedNative
|
||||
* pointers in their private date. See IS_WRAPPER_CLASS in
|
||||
* xpcprivate.h for details.
|
||||
*/
|
||||
void GetXPCWrappedNativeJSClassInfo(out JSClassConstPtr clazz,
|
||||
out JSGetObjectOps ops1,
|
||||
out JSGetObjectOps ops2);
|
||||
};
|
||||
|
|
|
@ -1861,6 +1861,23 @@ nsXPConnect::EvalInSandboxObject(const nsAString& source, JSContext *cx,
|
|||
#endif /* XPCONNECT_STANDALONE */
|
||||
}
|
||||
|
||||
/* void GetXPCWrappedNativeJSClassInfo(out JSClassConstPtr clazz, out JSObjectOpsConstPtr ops1, out JSObjectOpsConstPtr ops2); */
|
||||
NS_IMETHODIMP
|
||||
nsXPConnect::GetXPCWrappedNativeJSClassInfo(const JSClass **clazz,
|
||||
JSGetObjectOps *ops1,
|
||||
JSGetObjectOps *ops2)
|
||||
{
|
||||
// Expose the JSClass and JSGetObjectOps pointers used by
|
||||
// IS_WRAPPER_CLASS(). If that macro ever changes, this function
|
||||
// needs to stay in sync.
|
||||
|
||||
*clazz = &XPC_WN_NoHelper_JSClass.base;
|
||||
*ops1 = XPC_WN_GetObjectOpsNoCall;
|
||||
*ops2 = XPC_WN_GetObjectOpsWithCall;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */
|
||||
NS_IMETHODIMP
|
||||
nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
|
||||
|
|
|
@ -251,6 +251,14 @@ extern const char XPC_XPCONNECT_CONTRACTID[];
|
|||
*dest = result; \
|
||||
return (result || !src) ? NS_OK : NS_ERROR_OUT_OF_MEMORY
|
||||
|
||||
|
||||
// NOTE!!!
|
||||
//
|
||||
// If this ever changes,
|
||||
// nsScriptSecurityManager::doGetObjectPrincipal() *must* be updated
|
||||
// also!
|
||||
//
|
||||
// NOTE!!!
|
||||
#define IS_WRAPPER_CLASS(clazz) \
|
||||
((clazz) == &XPC_WN_NoHelper_JSClass.base || \
|
||||
(clazz)->getObjectOps == XPC_WN_GetObjectOpsNoCall || \
|
||||
|
|
Загрузка…
Ссылка в новой задаче