Bug 631135 - Objects created by or on behalf of fast natives and property ops (getters or setters) are parented to the wrong proto and global. r=lw,jst,mrbkap,bz, a=jst

--HG--
extra : rebase_source : a2f6a11ac3bcc7925cbf122057b694a0aafac970
This commit is contained in:
Jeff Walden 2011-02-08 17:20:06 -08:00
parent 1c47a5ff17
commit 414ac259f6
34 changed files with 904 additions and 480 deletions

View File

@ -13,7 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=246699
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=246699">Mozilla Bug 246699</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="load-frame"></iframe>
<iframe id="load-frame" src="http://example.com/"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
@ -49,11 +49,13 @@ function tryComponentsClasses()
return Components.classes["@mozilla.org/dummy;1"];
}
is(inciteCaps(tryChromeLoad), "denied-stack",
"should get stack for content-loading-chrome rejection");
is(inciteCaps(tryComponentsClasses), "denied-stack",
"should get stack for Components.classes rejection");
window.addEventListener("load", function()
{
is(inciteCaps(tryChromeLoad), "denied-stack",
"should get stack for content-loading-chrome rejection");
is(inciteCaps(tryComponentsClasses), "denied-stack",
"should get stack for Components.classes rejection");
}, false);
</script>
</pre>
</body>

View File

@ -5799,9 +5799,13 @@ CloneSimpleValues(JSContext* cx,
// RegExp objects.
if (js_ObjectIsRegExp(obj)) {
JSObject* global = JS_GetGlobalForScopeChain(cx);
if (!global) {
return NS_ERROR_FAILURE;
}
JSObject* proto;
if (!js_GetClassPrototype(cx, JS_GetScopeChain(cx), JSProto_RegExp,
&proto)) {
if (!js_GetClassPrototype(cx, global, JSProto_RegExp, &proto)) {
return NS_ERROR_FAILURE;
}
JSObject* newRegExp = js_CloneRegExpObject(cx, obj, proto);

View File

@ -5803,30 +5803,17 @@ nsGlobalWindow::CallerInnerWindow()
return nsnull;
}
JSObject *scope = nsnull;
JSStackFrame *fp = nsnull;
JS_FrameIterator(cx, &fp);
if (fp) {
while (fp->isDummyFrame()) {
if (!JS_FrameIterator(cx, &fp))
break;
}
if (fp)
scope = &fp->scopeChain();
}
if (!scope)
scope = JS_GetScopeChain(cx);
JSObject *callerGlobal;
if (!::JS_GetGlobalForCallingScript(cx, &callerGlobal) || !callerGlobal)
return nsnull;
JSAutoEnterCompartment ac;
if (!ac.enter(cx, scope))
if (!ac.enter(cx, callerGlobal))
return nsnull;
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
getter_AddRefs(wrapper));
GetWrappedNativeOfJSObject(cx, callerGlobal, getter_AddRefs(wrapper));
if (!wrapper)
return nsnull;

View File

@ -670,9 +670,25 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
// Check the amount of time this script has been running, or if the
// dialog is disabled.
JSObject* global = ::JS_GetGlobalForScopeChain(cx);
JSObject* global;
if (!::JS_GetGlobalForCallingScript(cx, &global)) {
return JS_FALSE;
}
if (!global) {
global = JS_GetGlobalObject(cx);
if (!global) {
return NS_ERROR_FAILURE;
}
OBJ_TO_INNER_OBJECT(cx, global);
if (!global) {
return NS_ERROR_FAILURE;
}
}
NS_ABORT_IF_FALSE(global != NULL, "operation callback without script?");
PRBool isTrackingChromeCodeTime =
global && xpc::AccessCheck::isChrome(global->getCompartment());
xpc::AccessCheck::isChrome(global->getCompartment());
if (duration < (isTrackingChromeCodeTime ?
sMaxChromeScriptRunTime : sMaxScriptRunTime)) {
return JS_TRUE;

View File

@ -190,19 +190,18 @@ nsJSUtils::GetCurrentlyRunningCodeWindowID(JSContext *aContext)
if (!aContext)
return 0;
PRUint64 windowID = 0;
JSObject *jsGlobal;
if (!JS_GetGlobalForCallingScript(aContext, &jsGlobal) || !jsGlobal)
return 0;
JSObject *jsGlobal = JS_GetGlobalForScopeChain(aContext);
if (jsGlobal) {
nsIScriptGlobalObject *scriptGlobal = GetStaticScriptGlobal(aContext,
jsGlobal);
if (scriptGlobal) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptGlobal);
if (win)
windowID = win->GetOuterWindow()->WindowID();
}
}
JSAutoEnterCompartment ac;
if (!ac.enter(aContext, jsGlobal))
return 0;
nsIScriptGlobalObject *sg = GetStaticScriptGlobal(aContext, jsGlobal);
if (!sg)
return 0;
return windowID;
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(sg);
return win ? win->GetOuterWindow()->WindowID() : 0;
}

View File

@ -114,7 +114,7 @@ ReturnKeyRange(JSContext* aCx,
nsIXPConnect* xpc = nsContentUtils::XPConnect();
NS_ASSERTION(xpc, "This should never be null!");
JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx));
JSObject* global = JS_GetGlobalForScopeChain(aCx);
NS_ENSURE_TRUE(global, JS_FALSE);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;

View File

@ -634,7 +634,7 @@ nsDOMWorkerFunctions::GetInstanceCommon(JSContext* aCx,
}
}
JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx));
JSObject* global = JS_GetGlobalForScopeChain(aCx);
if (!global) {
NS_ASSERTION(JS_IsExceptionPending(aCx), "Need to set an exception!");
return JS_FALSE;
@ -2533,8 +2533,7 @@ nsDOMWorker::ReadStructuredClone(JSContext* aCx,
if (JS_ReadBytes(aReader, &wrappedNative, sizeof(wrappedNative))) {
NS_ASSERTION(wrappedNative, "Null pointer?!");
JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx));
if (global) {
if (JSObject* global = JS_GetGlobalForScopeChain(aCx)) {
jsval val;
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
if (NS_SUCCEEDED(nsContentUtils::WrapNative(aCx, global, wrappedNative,

View File

@ -54,6 +54,7 @@ CPPSRCS = \
testCloneScript.cpp \
testConservativeGC.cpp \
testContexts.cpp \
testCrossGlobal.cpp \
testDebugger.cpp \
testDeepFreeze.cpp \
testDefineGetterSetterNonEnumerable.cpp \

View File

@ -0,0 +1,90 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
#include "tests.h"
static const char CODE[] =
"function f() "
"{ "
" return new otherGlobal.Array() instanceof otherGlobal.Array; "
"} "
"f() && f() && f(); ";
BEGIN_TEST(testCrossGlobal_call)
{
JSObject *otherGlobal = JS_NewGlobalObject(cx, basicGlobalClass());
CHECK(otherGlobal);
JSBool res = JS_InitStandardClasses(cx, otherGlobal);
CHECK(res);
res = JS_DefineProperty(cx, global, "otherGlobal", OBJECT_TO_JSVAL(otherGlobal),
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE);
CHECK(res);
uintN oldopts = JS_GetOptions(cx);
uintN newopts = oldopts & ~(JSOPTION_JIT | JSOPTION_METHODJIT | JSOPTION_PROFILING);
newopts |= JSOPTION_METHODJIT;
JS_SetOptions(cx, newopts);
jsval rv;
EVAL(CODE, &rv);
CHECK_SAME(rv, JSVAL_TRUE);
JS_SetOptions(cx, oldopts);
return true;
}
END_TEST(testCrossGlobal_call)
BEGIN_TEST(testCrossGlobal_compileAndGo)
{
JSObject *otherGlobal = JS_NewGlobalObject(cx, basicGlobalClass());
CHECK(otherGlobal);
JSBool res = JS_InitStandardClasses(cx, otherGlobal);
CHECK(res);
res = JS_DefineProperty(cx, global, "otherGlobal", OBJECT_TO_JSVAL(otherGlobal),
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE);
CHECK(res);
res = JS_DefineProperty(cx, otherGlobal, "otherGlobal", OBJECT_TO_JSVAL(otherGlobal),
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE);
CHECK(res);
uintN oldopts = JS_GetOptions(cx);
uintN newopts =
oldopts
& ~(JSOPTION_COMPILE_N_GO | JSOPTION_JIT | JSOPTION_METHODJIT | JSOPTION_PROFILING);
newopts |= JSOPTION_METHODJIT;
JS_SetOptions(cx, newopts);
jsval rv;
// Compile script
JSScript *script = JS_CompileScript(cx, global, CODE, strlen(CODE), __FILE__, __LINE__);
CHECK(script);
JSObject *scriptObj = JS_NewScriptObject(cx, script);
CHECK(scriptObj);
JS::Anchor<JSObject *> anch(scriptObj);
// Run script against new other global
res = JS_ExecuteScript(cx, otherGlobal, script, &rv);
CHECK(res);
CHECK_SAME(rv, JSVAL_TRUE);
// Run script against original global
res = JS_ExecuteScript(cx, global, script, &rv);
CHECK(res);
CHECK_SAME(rv, JSVAL_TRUE);
JS_SetOptions(cx, oldopts);
return true;
}
END_TEST(testCrossGlobal_compileAndGo)

View File

@ -1928,13 +1928,6 @@ JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
return js_GetClassObject(cx, obj, key, objp);
}
JS_PUBLIC_API(JSObject *)
JS_GetScopeChain(JSContext *cx)
{
CHECK_REQUEST(cx);
return GetScopeChain(cx);
}
JS_PUBLIC_API(JSObject *)
JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
{
@ -1946,7 +1939,24 @@ JS_PUBLIC_API(JSObject *)
JS_GetGlobalForScopeChain(JSContext *cx)
{
CHECK_REQUEST(cx);
return GetGlobalForScopeChain(cx);
return cx->getGlobalFromScopeChain();
}
JS_PUBLIC_API(JSBool)
JS_GetGlobalForCallingScript(JSContext *cx, JSObject **objp)
{
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
if (!fp) {
*objp = NULL;
return true;
}
JSObject *scope = JS_GetFrameScopeChain(cx, fp);
if (!scope)
return false;
*objp = scope->getGlobal();
return true;
}
JS_PUBLIC_API(jsval)

View File

@ -1098,15 +1098,40 @@ extern JS_PUBLIC_API(JSBool)
JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
JSObject **objp);
extern JS_PUBLIC_API(JSObject *)
JS_GetScopeChain(JSContext *cx);
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalForObject(JSContext *cx, JSObject *obj);
/*
* Returns the global for the currently executing method or of the object
* currently being accessed if a property access (get or set) is in progress.
* If no action is currently in progress, the context's global object is
* returned. If the context has no global, this method will report an error and
* return null.
*
* To illustrate: suppose a global G with a method defined by a JSNative
* corresponding to the property G.method. When JS_GetGlobalForScopeChain is
* invoked during execution of G.method, the object returned will be G. This is
* so if a script in G calls method, and it is also so if script in a different
* global G2 calls |G1.method()|, or extracts |G.method| and calls it, and so
* on. This behavior also applies for property accesses to an |obj.prop| if
* that property is represented by a |JSPropertyOp| and |JSStrictPropertyOp|
* pair: the global object will be that corresponding to |obj|.
*/
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalForScopeChain(JSContext *cx);
/*
* Returns the global of the most recent interpreted code if there is any.
*
* NB: This method ignores the current scope chain, any sense of privilege
* separation encapsulated in intervening stack frames, and so on. If you
* are attempting to determine the global object to expose it to script,
* this is almost certainly not the method you want! You *probably* want
* JS_GetGlobalForScopeChain instead.
*/
extern JS_PUBLIC_API(JSBool)
JS_GetGlobalForCallingScript(JSContext *cx, JSObject **objp);
#ifdef JS_HAS_CTYPES
/*
* Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes'

View File

@ -231,6 +231,8 @@ StackSpace::mark(JSTracer *trc)
/* This may be the only pointer to the initialVarObj. */
if (seg->hasInitialVarObj())
MarkObject(trc, seg->getInitialVarObj(), "varobj");
if (seg->hasLastNativeCalleeScope())
MarkObject(trc, *seg->lastNativeCalleeScope(), "lastNativeCalleeScope");
/* Mark slots/args trailing off of the last stack frame. */
JSStackFrame *fp = seg->getCurrentFrame();
@ -1991,6 +1993,12 @@ JSContext::JSContext(JSRuntime *rt)
busyArrays()
{}
void
JSContext::reportInactive()
{
JS_ReportErrorNumber(this, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
}
void
JSContext::resetCompartment()
{
@ -2084,7 +2092,9 @@ void
JSContext::saveActiveSegment()
{
JS_ASSERT(hasActiveSegment());
currentSegment->save(regs);
currentSegment->save(regs, lastNativeCalleeScope, lastNativeCalleeScopePtr);
lastNativeCalleeScope = NULL;
lastNativeCalleeScopePtr = NULL;
setCurrentRegs(NULL);
resetCompartment();
}
@ -2092,9 +2102,11 @@ JSContext::saveActiveSegment()
void
JSContext::restoreSegment()
{
js::StackSegment *ccs = currentSegment;
setCurrentRegs(ccs->getSuspendedRegs());
ccs->restore();
js::StackSegment *cs = currentSegment;
setCurrentRegs(cs->getSuspendedRegs());
lastNativeCalleeScopePtr = cs->lastNativeCalleeScopePtr();
lastNativeCalleeScope = cs->lastNativeCalleeScope();
cs->restore();
resetCompartment();
}

View File

@ -245,6 +245,10 @@ class StackSegment
/* Whether this segment was suspended by JS_SaveFrameChain. */
bool saved;
/* Maintained to implement getGlobalFromScopeChain. */
JSObject *savedLastNativeCalleeScope_;
void *savedLastNativeCalleeScopePtr_;
/* Align at 8 bytes on all platforms. */
#if JS_BITS_PER_WORD == 32
void *padding;
@ -260,7 +264,8 @@ class StackSegment
StackSegment()
: cx(NULL), previousInContext(NULL), previousInMemory(NULL),
initialFrame(NULL), suspendedRegs(NON_NULL_SUSPENDED_REGS),
initialVarObj(NULL), saved(false)
initialVarObj(NULL), saved(false), savedLastNativeCalleeScope_(NULL),
savedLastNativeCalleeScopePtr_(NULL)
{
JS_ASSERT(!inContext());
}
@ -348,19 +353,9 @@ class StackSegment
/* When isSuspended, transitioning isSaved <--> !isSaved */
void save(JSFrameRegs *regs) {
JS_ASSERT(!isSuspended());
suspend(regs);
saved = true;
JS_ASSERT(isSaved());
}
void save(JSFrameRegs *regs, JSObject *lastNativeCalleeScope, void *lastNativeCalleeScopePtr);
void restore() {
JS_ASSERT(isSaved());
saved = false;
resume();
JS_ASSERT(!isSuspended());
}
void restore();
/* Data available when inContext */
@ -416,6 +411,21 @@ class StackSegment
return *initialVarObj;
}
bool hasLastNativeCalleeScope() const {
JS_ASSERT(inContext());
return savedLastNativeCalleeScope_ != NULL;
}
JSObject *lastNativeCalleeScope() const {
JS_ASSERT(inContext());
return savedLastNativeCalleeScope_;
}
void *lastNativeCalleeScopePtr() const {
JS_ASSERT(inContext());
return savedLastNativeCalleeScopePtr_;
}
#ifdef DEBUG
JS_REQUIRES_STACK bool contains(const JSStackFrame *fp) const;
#endif
@ -623,8 +633,6 @@ class StackSpace
inline void popInvokeArgs(const InvokeArgsGuard &args);
inline void popInvokeFrame(const InvokeFrameGuard &ag);
inline Value *firstUnused() const;
inline bool isCurrentAndActive(JSContext *cx) const;
friend class AllFramesIter;
StackSegment *getCurrentSegment() const { return currentSegment; }
@ -634,6 +642,11 @@ class StackSpace
JS_FRIEND_API(bool) bumpCommit(Value *from, ptrdiff_t nvals) const;
#endif
/* The first stack location available to push new values and frames. */
inline js::Value *firstUnused() const;
public:
inline void *constFirstUnused() const;
public:
static const size_t CAPACITY_VALS = 512 * 1024;
static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(Value);
@ -1684,6 +1697,32 @@ struct JSContext
return !!regs;
}
/*
* An object created for the global of the currently executing native
* method, native getter, or native setter (or null if none is executing),
* used for scope chain computation. The exact identity of this value is
* unspecified: function calls and property accesses fill this with
* different values, and the trace JIT and method JIT don't update the
* value during intra-global-object method calls and property accesses.
*/
JSObject *lastNativeCalleeScope;
/*
* A JavaScript stack location associated with a native call/property
* access.
*/
void *lastNativeCalleeScopePtr;
/*
* Computes the global object corresponding to the current scope chain, as
* determined by the current callee if one exists, by the object being
* accessed if a native property operation is occurring, or by the context
* global object if one does not.
*/
inline JSObject *getGlobalFromScopeChain();
void reportInactive();
public:
friend class js::StackSpace;
friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, JSInterpMode);
@ -1768,7 +1807,7 @@ struct JSContext
return currentSegment;
}
inline js::RegExpStatics *regExpStatics();
inline js::RegExpStatics *getRegExpStatics();
/* Add the given segment to the list as the new active segment. */
void pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &regs);

View File

@ -49,35 +49,6 @@
#include "jsregexp.h"
#include "jsgc.h"
namespace js {
static inline JSObject *
GetGlobalForScopeChain(JSContext *cx)
{
/*
* This is essentially GetScopeChain(cx)->getGlobal(), but without
* falling off trace.
*
* This use of cx->fp, possibly on trace, is deliberate:
* cx->fp->scopeChain->getGlobal() returns the same object whether we're on
* trace or not, since we do not trace calls across global objects.
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
if (cx->hasfp())
return cx->fp()->scopeChain().getGlobal();
JSObject *scope = cx->globalObject;
if (!scope) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, scope);
return scope;
}
}
#ifdef JS_METHODJIT
inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment()
{
@ -85,6 +56,45 @@ inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment()
}
#endif
inline JSObject *
JSContext::getGlobalFromScopeChain()
{
if (regs) {
/*
* It's fine if the frame is stale on-trace, because we don't trace
* calls crossing globals.
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
/* Consult the frame if it's newer than any last native call. */
if (regs->fp > lastNativeCalleeScopePtr)
return regs->fp->scopeChain().getGlobal();
/* Otherwise the callee gives us our global object. */
JS_ASSERT(lastNativeCalleeScopePtr <= stack().constFirstUnused());
JS_ASSERT(currentSegment < lastNativeCalleeScopePtr);
return lastNativeCalleeScope->getGlobal();
}
/* If we have only native calls, consult the last one. */
if (lastNativeCalleeScope) {
JS_ASSERT(lastNativeCalleeScopePtr <= stack().constFirstUnused());
return lastNativeCalleeScope->getGlobal();
}
/*
* If no native call has occurred, this is a free-floating request for
* a global: return the context globalObject if possible.
*/
JSObject *globalObj = globalObject;
if (!globalObj) {
reportInactive();
return NULL;
}
OBJ_TO_INNER_OBJECT(this, globalObj);
return globalObj;
}
inline bool
JSContext::ensureGeneratorStackSpace()
{
@ -110,13 +120,37 @@ JSContext::computeNextFrame(JSStackFrame *fp)
}
inline js::RegExpStatics *
JSContext::regExpStatics()
JSContext::getRegExpStatics()
{
return js::RegExpStatics::extractFrom(js::GetGlobalForScopeChain(this));
JSObject *global = getGlobalFromScopeChain();
if (!global)
return NULL;
return js::RegExpStatics::extractFrom(global);
}
namespace js {
JS_ALWAYS_INLINE void
StackSegment::save(JSFrameRegs *regs, JSObject *lastNativeCalleeScope,
void *lastNativeCalleeScopePtr)
{
JS_ASSERT(!isSuspended());
suspend(regs);
saved = true;
savedLastNativeCalleeScope_ = lastNativeCalleeScope;
savedLastNativeCalleeScopePtr_ = lastNativeCalleeScopePtr;
JS_ASSERT(isSaved());
}
JS_ALWAYS_INLINE void
StackSegment::restore()
{
JS_ASSERT(isSaved());
saved = false;
resume();
JS_ASSERT(!isSuspended());
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSFrameRegs *
StackSegment::getCurrentRegs() const
{
@ -153,6 +187,12 @@ StackSpace::firstUnused() const
return invokeArgEnd;
}
JS_REQUIRES_STACK inline void *
StackSpace::constFirstUnused() const
{
return firstUnused();
}
/* Inline so we don't need the friend API. */
JS_ALWAYS_INLINE bool
@ -532,7 +572,7 @@ class CompartmentChecker
public:
explicit CompartmentChecker(JSContext *cx) : context(cx), compartment(cx->compartment) {
check(cx->hasfp() ? JS_GetGlobalForScopeChain(cx) : cx->globalObject);
check(cx->getGlobalFromScopeChain());
VOUCH_DOES_NOT_REQUIRE_STACK();
}
@ -690,6 +730,35 @@ assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
#undef START_ASSERT_SAME_COMPARTMENT
namespace detail {
class AutoScopeChainSetter {
JSContext * const cx;
JSObject * const oldLastNativeCalleeScope;
void * const oldLastNativeCalleeScopePtr;
JSObject * const scope;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
AutoScopeChainSetter(JSContext *cx, JSObject *scope, void *scopePtr
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: cx(cx),
oldLastNativeCalleeScope(cx->lastNativeCalleeScope),
oldLastNativeCalleeScopePtr(cx->lastNativeCalleeScopePtr),
scope(scope)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
cx->lastNativeCalleeScope = scope;
cx->lastNativeCalleeScopePtr = scopePtr;
}
~AutoScopeChainSetter() {
cx->lastNativeCalleeScope = oldLastNativeCalleeScope;
cx->lastNativeCalleeScopePtr = oldLastNativeCalleeScopePtr;
}
};
}
STATIC_PRECONDITION_ASSUME(ubound(vp) >= argc + 2)
JS_ALWAYS_INLINE bool
CallJSNative(JSContext *cx, js::Native native, uintN argc, js::Value *vp)
@ -697,6 +766,7 @@ CallJSNative(JSContext *cx, js::Native native, uintN argc, js::Value *vp)
#ifdef DEBUG
JSBool alreadyThrowing = cx->isExceptionPending();
#endif
detail::AutoScopeChainSetter scs(cx, &vp[0].toObject(), vp);
assertSameCompartment(cx, ValueArray(vp, argc + 2));
JSBool ok = native(cx, argc, vp);
if (ok) {
@ -747,6 +817,15 @@ JS_ALWAYS_INLINE bool
CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp)
{
assertSameCompartment(cx, obj, id, *vp);
/*
* This property access may occur not in relation to a stack location, so
* we can't use |vp| here. However, since we use the location only in
* comparisons, to determine when to refer to the last interpreted frame's
* scope chain versus the last native callee's global object, the first
* unused location at the end of the stack will suffice.
*/
detail::AutoScopeChainSetter scs(cx, obj, cx->stack().constFirstUnused());
JSBool ok = op(cx, obj, id, vp);
if (ok)
assertSameCompartment(cx, obj, *vp);
@ -758,6 +837,9 @@ CallJSPropertyOpSetter(JSContext *cx, js::StrictPropertyOp op, JSObject *obj, js
JSBool strict, js::Value *vp)
{
assertSameCompartment(cx, obj, id, *vp);
/* See the comment in CallJSPropertyOp for an explanation. */
detail::AutoScopeChainSetter scs(cx, obj, cx->stack().constFirstUnused());
return op(cx, obj, id, strict, vp);
}

View File

@ -219,19 +219,12 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
* Wrappers should really be parented to the wrapped parent of the wrapped
* object, but in that case a wrapped global object would have a NULL
* parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead
,
* we parent all wrappers to the global object in their home compartment.
* This loses us some transparency, and is generally very cheesy.
*/
JSObject *global;
if (cx->hasfp()) {
global = cx->fp()->scopeChain().getGlobal();
} else {
global = cx->globalObject;
OBJ_TO_INNER_OBJECT(cx, global);
if (!global)
return false;
}
JSObject *global = cx->getGlobalFromScopeChain();
if (!global)
return false;
/* Unwrap incoming objects. */
if (vp->isObject()) {

View File

@ -158,33 +158,6 @@ JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
#endif
}
JSObject *
js::GetScopeChain(JSContext *cx)
{
JSStackFrame *fp = js_GetTopStackFrame(cx);
if (!fp) {
/*
* There is no code active on this context. In place of an actual
* scope chain, use the context's global object, which is set in
* js_InitFunctionAndObjectClasses, and which represents the default
* scope chain for the embedding. See also js_FindClassObject.
*
* For embeddings that use the inner and outer object hooks, the inner
* object represents the ultimate global object, with the outer object
* acting as a stand-in.
*/
JSObject *obj = cx->globalObject;
if (!obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, obj);
return obj;
}
return GetScopeChain(cx, fp);
}
/*
* This computes the blockChain by iterating through the bytecode
* of the current script until it reaches the PC. Each time it sees

View File

@ -803,9 +803,6 @@ GetBlockChain(JSContext *cx, JSStackFrame *fp);
extern JSObject *
GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
extern JSObject *
GetScopeChain(JSContext *cx);
/*
* Refresh and return fp->scopeChain. It may be stale if block scopes are
* active but not yet reflected by objects in the scope chain. If a block

View File

@ -4242,33 +4242,17 @@ JSBool
js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
Value *vp, Class *clasp)
{
JSStackFrame *fp;
JSObject *obj, *cobj, *pobj;
jsid id;
JSProperty *prop;
const Shape *shape;
/*
* Find the global object. Use cx->fp() directly to avoid falling off
* trace; all JIT-elided stack frames have the same global object as
* cx->fp().
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
if (!start && (fp = cx->maybefp()) != NULL)
start = &fp->scopeChain();
if (start) {
/* Find the topmost object in the scope chain. */
do {
obj = start;
start = obj->getParent();
} while (start);
obj = start->getGlobal();
} else {
obj = cx->globalObject;
if (!obj) {
vp->setUndefined();
return JS_TRUE;
}
obj = cx->getGlobalFromScopeChain();
if (!obj)
return JS_FALSE;
}
OBJ_TO_INNER_OBJECT(cx, obj);
@ -6189,15 +6173,9 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
if (protoKey != JSProto_Null) {
if (!scopeobj) {
if (cx->hasfp())
scopeobj = &cx->fp()->scopeChain();
if (!scopeobj) {
scopeobj = cx->globalObject;
if (!scopeobj) {
*protop = NULL;
return true;
}
}
scopeobj = cx->getGlobalFromScopeChain();
if (!scopeobj)
return false;
}
scopeobj = scopeobj->getGlobal();
if (scopeobj->isGlobal()) {

View File

@ -970,15 +970,9 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind)
JS_ASSERT(protoKey != JSProto_Null);
/* NB: inline-expanded and specialized version of js_GetClassPrototype. */
JSObject *global;
if (!cx->hasfp()) {
global = cx->globalObject;
OBJ_TO_INNER_OBJECT(cx, global);
if (!global)
return NULL;
} else {
global = cx->fp()->scopeChain().getGlobal();
}
JSObject *global = cx->getGlobalFromScopeChain();
if (!global)
return NULL;
JS_ASSERT(global->isGlobal());
const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);

View File

@ -8952,7 +8952,10 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
JSObject *obj;
if (context->hasfp()) {
obj = RegExp::createObject(context, context->regExpStatics(),
RegExpStatics *res = context->getRegExpStatics();
if (!res)
return NULL;
obj = RegExp::createObject(context, res,
tokenStream.getTokenbuf().begin(),
tokenStream.getTokenbuf().length(),
tokenStream.currentToken().t_reflags);

View File

@ -150,7 +150,9 @@ js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
*/
assertSameCompartment(cx, obj, clone);
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->getRegExpStatics();
if (!res)
return NULL;
RegExp *re = RegExp::extractFrom(obj);
{
uint32 origFlags = re->getFlags();
@ -401,7 +403,9 @@ regexp_resolve(JSContext *cx, JSObject *obj, jsid id, uint32 flags, JSObject **o
static JSBool \
name(JSContext *cx, JSObject *obj, jsid id, jsval *vp) \
{ \
RegExpStatics *res = cx->regExpStatics(); \
RegExpStatics *res = cx->getRegExpStatics(); \
if (!res) \
return false; \
code; \
}
@ -427,7 +431,9 @@ DEFINE_STATIC_GETTER(static_paren9_getter, return res->createParen(cx, 9,
static JSBool \
name(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) \
{ \
RegExpStatics *res = cx->regExpStatics(); \
RegExpStatics *res = cx->getRegExpStatics(); \
if (!res) \
return false; \
code; \
return true; \
}
@ -672,7 +678,10 @@ EscapeNakedForwardSlashes(JSContext *cx, JSString *unescaped)
static bool
SwapRegExpInternals(JSContext *cx, JSObject *obj, Value *rval, JSString *str, uint32 flags = 0)
{
flags |= cx->regExpStatics()->getFlags();
RegExpStatics *res = cx->getRegExpStatics();
if (!res)
return false;
flags |= res->getFlags();
AlreadyIncRefed<RegExp> re = RegExp::create(cx, str, flags);
if (!re)
return false;
@ -713,7 +722,9 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool te
lastIndex = 0;
}
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->getRegExpStatics();
if (!res)
return false;
JSString *input;
if (argc) {

View File

@ -1876,8 +1876,8 @@ str_match(JSContext *cx, uintN argc, Value *vp)
AutoObjectRooter array(cx);
MatchArgType arg = array.addr();
RegExpStatics *res = cx->regExpStatics();
if (!DoMatch(cx, res, vp, str, *rep, MatchCallback, arg, MATCH_ARGS))
RegExpStatics *res = cx->getRegExpStatics();
if (!res || !DoMatch(cx, res, vp, str, *rep, MatchCallback, arg, MATCH_ARGS))
return false;
/* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
@ -1906,7 +1906,9 @@ str_search(JSContext *cx, uintN argc, Value *vp)
if (!rep)
return false;
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->getRegExpStatics();
if (!res)
return false;
size_t i = 0;
if (!rep->re().execute(cx, res, str, &i, true, vp))
return false;
@ -2357,7 +2359,9 @@ str_replace_regexp(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata)
rdata.leftIndex = 0;
rdata.calledBack = false;
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->getRegExpStatics();
if (!res)
return false;
if (!DoMatch(cx, res, vp, rdata.str, *rep, ReplaceRegExpCallback, &rdata, REPLACE_ARGS))
return false;
@ -2697,7 +2701,9 @@ str_split(JSContext *cx, uintN argc, Value *vp)
AutoValueVector splits(cx);
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = cx->getRegExpStatics();
if (!res)
return false;
jsint i, j;
uint32 len = i = 0;
while ((j = find_split(cx, res, str, re, &i, sep)) >= 0) {

View File

@ -1677,6 +1677,32 @@ GetXMLSettingFlags(JSContext *cx, uintN *flagsp)
return true;
}
static JSObject *
GetXMLScopeChain(JSContext *cx)
{
if (JSStackFrame *fp = js_GetTopStackFrame(cx))
return GetScopeChain(cx, fp);
/*
* There is no code active on this context. In place of an actual scope
* chain, use the context's global object, which is set in
* s_InitFunctionAndObjectClasses, and which represents the default scope
* chain for the embedding. See also js_FindClassObject.
*
* For embeddings that use the inner and outer object hooks, the inner
* object represents the ultimate global object, with the outer object
* acting as a stand-in.
*/
JSObject *obj = cx->globalObject;
if (!obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, obj);
return obj;
}
static JSXML *
ParseXMLSource(JSContext *cx, JSString *src)
{
@ -1756,7 +1782,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
{
Parser parser(cx);
if (parser.init(chars, length, filename, lineno, cx->findVersion())) {
JSObject *scopeChain = GetScopeChain(cx);
JSObject *scopeChain = GetXMLScopeChain(cx);
if (!scopeChain) {
cx->free(chars);
return NULL;
@ -7231,7 +7257,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
JSObject *ns, *obj, *tmp;
jsval v;
JSObject *scopeChain = GetScopeChain(cx);
JSObject *scopeChain = GetXMLScopeChain(cx);
obj = NULL;
for (tmp = scopeChain; tmp; tmp = tmp->getParent()) {

View File

@ -808,9 +808,19 @@ class CallCompiler : public BaseCompiler
if (!CallJSNative(cx, fun->u.n.native, ic.frameSize.getArgc(f), vp))
THROWV(true);
/* Right now, take slow-path for IC misses or multiple stubs. */
if (ic.fastGuardedNative || ic.hasJsFunCheck)
/*
* Right now, take slow-path for IC misses or multiple stubs. Also take
* it if the call crosses, or might cross, globals: in that case
* JSContext::getGlobalFromScopeChain requires we note the change of
* global.
*/
if (ic.fastGuardedNative ||
ic.hasJsFunCheck ||
!f.regs.fp->script()->compileAndGo ||
obj->getGlobal() != f.regs.fp->scopeChain().getGlobal())
{
return true;
}
/* Native MIC needs to warm up first. */
if (!ic.hit) {

View File

@ -4356,6 +4356,40 @@ StringStats(JSContext *cx, uintN argc, jsval *vp)
return true;
}
enum CompartmentKind { SAME_COMPARTMENT, NEW_COMPARTMENT };
static JSObject *
NewGlobalObject(JSContext *cx, CompartmentKind compartment);
JSBool
NewGlobal(JSContext *cx, uintN argc, jsval *vp)
{
if (argc != 1 || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[0])) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "newGlobal");
return false;
}
JSString *str = JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]);
JSBool equalSame = JS_FALSE, equalNew = JS_FALSE;
if (!JS_StringEqualsAscii(cx, str, "same-compartment", &equalSame) ||
!JS_StringEqualsAscii(cx, str, "new-compartment", &equalNew)) {
return false;
}
if (!equalSame && !equalNew) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "newGlobal");
return false;
}
JSObject *global = NewGlobalObject(cx, equalSame ? SAME_COMPARTMENT : NEW_COMPARTMENT);
if (!global)
return false;
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(global));
return true;
}
static JSFunctionSpec shell_functions[] = {
JS_FN("version", Version, 0,0),
JS_FN("revertVersion", RevertVersion, 0,0),
@ -4452,6 +4486,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("mjitstats", MJitStats, 0,0),
#endif
JS_FN("stringstats", StringStats, 0,0),
JS_FN("newGlobal", NewGlobal, 1,0),
JS_FS_END
};
@ -4477,7 +4512,7 @@ static const char *const shell_help_messages[] = {
"assertEq(actual, expected[, msg])\n"
" Throw if the first two arguments are not the same (both +0 or both -0,\n"
" both NaN, or non-zero and ===)",
"assertJit() Throw if the calling function failed to JIT\n",
"assertJit() Throw if the calling function failed to JIT",
"gc() Run the garbage collector",
#ifdef JS_GCMETER
"gcstats() Print garbage collector statistics",
@ -4522,7 +4557,7 @@ static const char *const shell_help_messages[] = {
"dumpObject() Dump an internal representation of an object",
"notes([fun]) Show source notes for functions",
"tracing([true|false|filename]) Turn bytecode execution tracing on/off.\n"
" With filename, send to file.\n",
" With filename, send to file.",
"stats([string ...]) Dump 'arena', 'atom', 'global' stats",
#endif
#ifdef TEST_CVTARGS
@ -4573,24 +4608,37 @@ static const char *const shell_help_messages[] = {
" Get/Set the limit in seconds for the execution time for the current context.\n"
" A negative value (default) means that the execution time is unlimited.",
"elapsed() Execution time elapsed for the current context.",
"parent(obj) Returns the parent of obj.\n",
"wrap(obj) Wrap an object into a noop wrapper.\n",
"serialize(sd) Serialize sd using JS_WriteStructuredClone. Returns a TypedArray.\n",
"deserialize(a) Deserialize data generated by serialize.\n",
"parent(obj) Returns the parent of obj.",
"wrap(obj) Wrap an object into a noop wrapper.",
"serialize(sd) Serialize sd using JS_WriteStructuredClone. Returns a TypedArray.",
"deserialize(a) Deserialize data generated by serialize.",
#ifdef JS_METHODJIT
"mjitstats() Return stats on mjit memory usage.\n",
"mjitstats() Return stats on mjit memory usage.",
#endif
"stringstats() Return stats on string memory usage.\n"
"stringstats() Return stats on string memory usage.",
"newGlobal(kind) Return a new global object, in the current\n"
" compartment if kind === 'same-compartment' or in a\n"
" new compartment if kind === 'new-compartment'",
/* Keep these last: see the static assertion below. */
#ifdef MOZ_PROFILING
"startProfiling() Start a profiling session.\n"
" Profiler must be running with programatic sampling\n"
"stopProfiling() Stop a running profiling session"
" Profiler must be running with programatic sampling",
"stopProfiling() Stop a running profiling session\n"
#endif
};
#ifdef MOZ_PROFILING
#define PROFILING_FUNCTION_COUNT 2
#else
#define PROFILING_FUNCTION_COUNT 0
#endif
/* Help messages must match shell functions. */
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) + 1 ==
JS_ARRAY_LENGTH(shell_functions));
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - PROFILING_FUNCTION_COUNT ==
JS_ARRAY_LENGTH(shell_functions) - 1 /* JS_FS_END */);
#undef PROFILING_FUNCTION_COUNT
#ifdef DEBUG
static void
@ -4599,12 +4647,13 @@ CheckHelpMessages()
const char *const *m;
const char *lp;
/* Each message must begin with "function_name(" prefix. */
/* Messages begin with "function_name(" prefix and don't end with \n. */
for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages); ++m) {
lp = strchr(*m, '(');
JS_ASSERT(lp);
JS_ASSERT(memcmp(shell_functions[m - shell_help_messages].name,
*m, lp - *m) == 0);
JS_ASSERT((*m)[strlen(*m) - 1] != '\n');
}
}
#else
@ -5424,46 +5473,52 @@ DestroyContext(JSContext *cx, bool withGC)
}
static JSObject *
NewGlobalObject(JSContext *cx)
NewGlobalObject(JSContext *cx, CompartmentKind compartment)
{
JSObject *glob = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
JSObject *glob = (compartment == NEW_COMPARTMENT)
? JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL)
: JS_NewGlobalObject(cx, &global_class);
if (!glob)
return NULL;
JSAutoEnterCompartment ac;
if (!ac.enter(cx, glob))
return NULL;
{
JSAutoEnterCompartment ac;
if (!ac.enter(cx, glob))
return NULL;
#ifdef LAZY_STANDARD_CLASSES
JS_SetGlobalObject(cx, glob);
#else
if (!JS_InitStandardClasses(cx, glob))
return NULL;
#ifndef LAZY_STANDARD_CLASSES
if (!JS_InitStandardClasses(cx, glob))
return NULL;
#endif
#ifdef JS_HAS_CTYPES
if (!JS_InitCTypesClass(cx, glob))
return NULL;
if (!JS_InitCTypesClass(cx, glob))
return NULL;
#endif
if (!JS::RegisterPerfMeasurement(cx, glob))
return NULL;
if (!JS_DefineFunctions(cx, glob, shell_functions) ||
!JS_DefineProfilingFunctions(cx, glob)) {
return NULL;
if (!JS::RegisterPerfMeasurement(cx, glob))
return NULL;
if (!JS_DefineFunctions(cx, glob, shell_functions) ||
!JS_DefineProfilingFunctions(cx, glob)) {
return NULL;
}
JSObject *it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0);
if (!it)
return NULL;
if (!JS_DefineProperties(cx, it, its_props))
return NULL;
if (!JS_DefineFunctions(cx, it, its_methods))
return NULL;
if (!JS_DefineProperty(cx, glob, "custom", JSVAL_VOID, its_getter,
its_setter, 0))
return NULL;
if (!JS_DefineProperty(cx, glob, "customRdOnly", JSVAL_VOID, its_getter,
its_setter, JSPROP_READONLY))
return NULL;
}
JSObject *it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0);
if (!it)
return NULL;
if (!JS_DefineProperties(cx, it, its_props))
return NULL;
if (!JS_DefineFunctions(cx, it, its_methods))
return NULL;
if (!JS_DefineProperty(cx, glob, "custom", JSVAL_VOID, its_getter,
its_setter, 0))
return NULL;
if (!JS_DefineProperty(cx, glob, "customRdOnly", JSVAL_VOID, its_getter,
its_setter, JSPROP_READONLY))
if (compartment == NEW_COMPARTMENT && !JS_WrapObject(cx, &glob))
return NULL;
return glob;
@ -5474,7 +5529,7 @@ Shell(JSContext *cx, int argc, char **argv, char **envp)
{
JSAutoRequest ar(cx);
JSObject *glob = NewGlobalObject(cx);
JSObject *glob = NewGlobalObject(cx, NEW_COMPARTMENT);
if (!glob)
return 1;
@ -5482,6 +5537,8 @@ Shell(JSContext *cx, int argc, char **argv, char **envp)
if (!ac.enter(cx, glob))
return 1;
JS_SetGlobalObject(cx, glob);
JSObject *envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0);
if (!envobj || !JS_SetPrivate(cx, envobj, envp))
return 1;
@ -5518,7 +5575,7 @@ Shell(JSContext *cx, int argc, char **argv, char **envp)
class ShellWorkerHooks : public js::workers::WorkerHooks {
public:
JSObject *newGlobalObject(JSContext *cx) {
return NewGlobalObject(cx);
return NewGlobalObject(cx, NEW_COMPARTMENT);
}
};
ShellWorkerHooks hooks;

View File

@ -0,0 +1,41 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = 'cross-global-settings.js';
//-----------------------------------------------------------------------------
var BUGNUMBER = 631135;
var summary =
"Look at the callee's global.XML.* setting values, not the caller's";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var otherGlobal = newGlobal("same-compartment");
otherGlobal.XML.prettyPrinting = true;
otherGlobal.XML.prettyIndent = 2;
otherGlobal.indent = " ";
XML.prettyPrinting = true;
XML.prettyIndent = 16;
var indent = " " +
" " +
" " +
" ";
var str = otherGlobal.XML("<a><b/><c/></a>").toXMLString();
assertEq(str.indexOf(indent), -1);
assertEq(str.indexOf(otherGlobal.indent) > 0, true);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("All tests passed!");

View File

@ -22,3 +22,4 @@ script regress-450871-02.js
script regress-462734-01.js
script extensibility.js
script regress-595207.js
skip-if(!xulRuntime.shell) script cross-global-settings.js

View File

@ -0,0 +1,70 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
//-----------------------------------------------------------------------------
var BUGNUMBER = 631135;
var summary =
"Objects created by/for natives are created for the caller's scope, not " +
"for the native's scope";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var otherGlobal = newGlobal("same-compartment");
function makeArray()
{
return new otherGlobal.Array();
}
var a;
a = makeArray();
assertEq(a instanceof otherGlobal.Array, true);
assertEq(a instanceof Array, false);
a = makeArray();
assertEq(a instanceof otherGlobal.Array, true);
assertEq(a instanceof Array, false);
a = makeArray();
assertEq(a instanceof otherGlobal.Array, true);
assertEq(a instanceof Array, false);
for (var i = 0; i < 3; i++)
{
a = new otherGlobal.Array();
assertEq(a instanceof otherGlobal.Array, true);
assertEq(a instanceof Array, false);
}
var res = otherGlobal.Array.prototype.slice.call([1, 2, 3], 0, 1);
assertEq(res instanceof otherGlobal.Array, true);
assertEq(res instanceof Array, false);
var obj = { p: 1 };
var desc = otherGlobal.Object.getOwnPropertyDescriptor(obj, "p");
assertEq(desc instanceof otherGlobal.Object, true);
assertEq(desc instanceof Object, false);
try
{
otherGlobal.Function.prototype.call.call(null);
var err = "no error";
}
catch (e)
{
err = e;
}
assertEq(err instanceof otherGlobal.TypeError, true,
"bad error: " + err);
assertEq(err instanceof TypeError, false, "bad error: " + err);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("All tests passed!");

View File

@ -9,6 +9,7 @@ script bug352085.js
script bug472534.js
script bug496985.js
script bug566661.js
skip-if(!xulRuntime.shell) script cross-global-call.js # needs newGlobal()
script eval-native-callback-is-indirect.js
script extension-methods-reject-null-undefined-this.js
skip-if(!xulRuntime.shell) script function-definition-with.js # needs evaluate()

View File

@ -3630,11 +3630,17 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
{
JSAutoRequest req(cx);
callingScope = JS_GetScopeChain(cx);
if (!callingScope) {
if (!JS_GetGlobalForCallingScript(cx, &callingScope)) {
return NS_ERROR_FAILURE;
}
callingScope = JS_GetGlobalForObject(cx, callingScope);
if (!callingScope) {
callingScope = JS_GetGlobalObject(cx);
if (!callingScope)
return NS_ERROR_FAILURE;
OBJ_TO_INNER_OBJECT(cx, callingScope);
if (!callingScope)
return NS_ERROR_FAILURE;
}
}
nsRefPtr<ContextHolder> sandcx = new ContextHolder(cx, sandbox);

View File

@ -317,10 +317,9 @@ XPCThrower::ThrowExceptionObject(JSContext* cx, nsIException* e)
}
else if((xpc = nsXPConnect::GetXPConnect()))
{
JSObject* glob = JS_GetScopeChain(cx);
JSObject* glob = JS_GetGlobalForScopeChain(cx);
if(!glob)
return JS_FALSE;
glob = JS_GetGlobalForObject(cx, glob);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = xpc->WrapNative(cx, glob, e,

View File

@ -234,37 +234,28 @@ GetPrincipal(JSObject *obj)
bool
AccessCheck::documentDomainMakesSameOrigin(JSContext *cx, JSObject *obj)
{
JSObject *scope = nsnull;
JSStackFrame *fp = nsnull;
JS_FrameIterator(cx, &fp);
if (fp) {
while (fp->isDummyFrame()) {
if (!JS_FrameIterator(cx, &fp))
break;
}
if (fp)
scope = &fp->scopeChain();
JSObject *scope;
if (!JS_GetGlobalForCallingScript(cx, &scope))
return false;
if (!scope) {
scope = JS_GetGlobalForScopeChain(cx);
if (!scope)
return false;
}
if (!scope)
scope = JS_GetScopeChain(cx);
nsIPrincipal *subject;
nsIPrincipal *object;
{
JSAutoEnterCompartment ac;
if (!ac.enter(cx, scope))
return false;
subject = GetPrincipal(JS_GetGlobalForObject(cx, scope));
subject = GetPrincipal(scope);
}
if (!subject)
return false;
nsIPrincipal *object;
{
JSAutoEnterCompartment ac;

File diff suppressed because it is too large Load Diff

View File

@ -112,11 +112,7 @@ Module::Call(nsIXPConnectWrappedNative* wrapper,
jsval* vp,
PRBool* _retval)
{
JSObject* scope = JS_GetScopeChain(cx);
if (!scope)
return NS_ERROR_NOT_AVAILABLE;
JSObject* global = JS_GetGlobalForObject(cx, scope);
JSObject* global = JS_GetGlobalForScopeChain(cx);
if (!global)
return NS_ERROR_NOT_AVAILABLE;