js/src/jscntxtinlines.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef jscntxtinlines_h
     8 #define jscntxtinlines_h
    10 #include "jscntxt.h"
    11 #include "jscompartment.h"
    13 #include "jsiter.h"
    14 #include "jsworkers.h"
    16 #include "builtin/Object.h"
    17 #include "jit/IonFrames.h"
    18 #include "vm/ForkJoin.h"
    19 #include "vm/Interpreter.h"
    20 #include "vm/ProxyObject.h"
    22 namespace js {
    24 #ifdef JS_CRASH_DIAGNOSTICS
    25 class CompartmentChecker
    26 {
    27     JSCompartment *compartment;
    29   public:
    30     explicit CompartmentChecker(ExclusiveContext *cx)
    31       : compartment(cx->compartment())
    32     {
    33 #ifdef DEBUG
    34         // In debug builds, make sure the embedder passed the cx it claimed it
    35         // was going to use.
    36         JSContext *activeContext = nullptr;
    37         if (cx->isJSContext())
    38             activeContext = cx->asJSContext()->runtime()->activeContext;
    39         JS_ASSERT_IF(activeContext, cx == activeContext);
    40 #endif
    41     }
    43     /*
    44      * Set a breakpoint here (break js::CompartmentChecker::fail) to debug
    45      * compartment mismatches.
    46      */
    47     static void fail(JSCompartment *c1, JSCompartment *c2) {
    48         printf("*** Compartment mismatch %p vs. %p\n", (void *) c1, (void *) c2);
    49         MOZ_CRASH();
    50     }
    52     static void fail(JS::Zone *z1, JS::Zone *z2) {
    53         printf("*** Zone mismatch %p vs. %p\n", (void *) z1, (void *) z2);
    54         MOZ_CRASH();
    55     }
    57     /* Note: should only be used when neither c1 nor c2 may be the atoms compartment. */
    58     static void check(JSCompartment *c1, JSCompartment *c2) {
    59         JS_ASSERT(!c1->runtimeFromAnyThread()->isAtomsCompartment(c1));
    60         JS_ASSERT(!c2->runtimeFromAnyThread()->isAtomsCompartment(c2));
    61         if (c1 != c2)
    62             fail(c1, c2);
    63     }
    65     void check(JSCompartment *c) {
    66         if (c && !compartment->runtimeFromAnyThread()->isAtomsCompartment(c)) {
    67             if (!compartment)
    68                 compartment = c;
    69             else if (c != compartment)
    70                 fail(compartment, c);
    71         }
    72     }
    74     void checkZone(JS::Zone *z) {
    75         if (compartment && z != compartment->zone())
    76             fail(compartment->zone(), z);
    77     }
    79     void check(JSObject *obj) {
    80         if (obj)
    81             check(obj->compartment());
    82     }
    84     template<typename T>
    85     void check(const Rooted<T>& rooted) {
    86         check(rooted.get());
    87     }
    89     template<typename T>
    90     void check(Handle<T> handle) {
    91         check(handle.get());
    92     }
    94     void check(JSString *str) {
    95         if (!str->isAtom())
    96             checkZone(str->zone());
    97     }
    99     void check(const js::Value &v) {
   100         if (v.isObject())
   101             check(&v.toObject());
   102         else if (v.isString())
   103             check(v.toString());
   104     }
   106     void check(const ValueArray &arr) {
   107         for (size_t i = 0; i < arr.length; i++)
   108             check(arr.array[i]);
   109     }
   111     void check(const JSValueArray &arr) {
   112         for (size_t i = 0; i < arr.length; i++)
   113             check(arr.array[i]);
   114     }
   116     void check(const JS::HandleValueArray &arr) {
   117         for (size_t i = 0; i < arr.length(); i++)
   118             check(arr[i]);
   119     }
   121     void check(const CallArgs &args) {
   122         for (Value *p = args.base(); p != args.end(); ++p)
   123             check(*p);
   124     }
   126     void check(jsid id) {
   127         if (JSID_IS_OBJECT(id))
   128             check(JSID_TO_OBJECT(id));
   129     }
   131     void check(JSIdArray *ida) {
   132         if (ida) {
   133             for (int i = 0; i < ida->length; i++) {
   134                 if (JSID_IS_OBJECT(ida->vector[i]))
   135                     check(ida->vector[i]);
   136             }
   137         }
   138     }
   140     void check(JSScript *script) {
   141         if (script)
   142             check(script->compartment());
   143     }
   145     void check(InterpreterFrame *fp);
   146     void check(AbstractFramePtr frame);
   147 };
   148 #endif /* JS_CRASH_DIAGNOSTICS */
   150 /*
   151  * Don't perform these checks when called from a finalizer. The checking
   152  * depends on other objects not having been swept yet.
   153  */
   154 #define START_ASSERT_SAME_COMPARTMENT()                                       \
   155     if (!cx->isExclusiveContext())                                            \
   156         return;                                                               \
   157     if (cx->isJSContext() && cx->asJSContext()->runtime()->isHeapBusy())      \
   158         return;                                                               \
   159     CompartmentChecker c(cx->asExclusiveContext())
   161 template <class T1> inline void
   162 assertSameCompartment(ThreadSafeContext *cx, const T1 &t1)
   163 {
   164 #ifdef JS_CRASH_DIAGNOSTICS
   165     START_ASSERT_SAME_COMPARTMENT();
   166     c.check(t1);
   167 #endif
   168 }
   170 template <class T1> inline void
   171 assertSameCompartmentDebugOnly(ThreadSafeContext *cx, const T1 &t1)
   172 {
   173 #ifdef DEBUG
   174     START_ASSERT_SAME_COMPARTMENT();
   175     c.check(t1);
   176 #endif
   177 }
   179 template <class T1, class T2> inline void
   180 assertSameCompartment(ThreadSafeContext *cx, const T1 &t1, const T2 &t2)
   181 {
   182 #ifdef JS_CRASH_DIAGNOSTICS
   183     START_ASSERT_SAME_COMPARTMENT();
   184     c.check(t1);
   185     c.check(t2);
   186 #endif
   187 }
   189 template <class T1, class T2, class T3> inline void
   190 assertSameCompartment(ThreadSafeContext *cx, const T1 &t1, const T2 &t2, const T3 &t3)
   191 {
   192 #ifdef JS_CRASH_DIAGNOSTICS
   193     START_ASSERT_SAME_COMPARTMENT();
   194     c.check(t1);
   195     c.check(t2);
   196     c.check(t3);
   197 #endif
   198 }
   200 template <class T1, class T2, class T3, class T4> inline void
   201 assertSameCompartment(ThreadSafeContext *cx,
   202                       const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4)
   203 {
   204 #ifdef JS_CRASH_DIAGNOSTICS
   205     START_ASSERT_SAME_COMPARTMENT();
   206     c.check(t1);
   207     c.check(t2);
   208     c.check(t3);
   209     c.check(t4);
   210 #endif
   211 }
   213 template <class T1, class T2, class T3, class T4, class T5> inline void
   214 assertSameCompartment(ThreadSafeContext *cx,
   215                       const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5)
   216 {
   217 #ifdef JS_CRASH_DIAGNOSTICS
   218     START_ASSERT_SAME_COMPARTMENT();
   219     c.check(t1);
   220     c.check(t2);
   221     c.check(t3);
   222     c.check(t4);
   223     c.check(t5);
   224 #endif
   225 }
   227 #undef START_ASSERT_SAME_COMPARTMENT
   229 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
   230 MOZ_ALWAYS_INLINE bool
   231 CallJSNative(JSContext *cx, Native native, const CallArgs &args)
   232 {
   233     JS_CHECK_RECURSION(cx, return false);
   235 #ifdef DEBUG
   236     bool alreadyThrowing = cx->isExceptionPending();
   237 #endif
   238     assertSameCompartment(cx, args);
   239     bool ok = native(cx, args.length(), args.base());
   240     if (ok) {
   241         assertSameCompartment(cx, args.rval());
   242         JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
   243     }
   244     return ok;
   245 }
   247 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
   248 MOZ_ALWAYS_INLINE bool
   249 CallNativeImpl(JSContext *cx, NativeImpl impl, const CallArgs &args)
   250 {
   251 #ifdef DEBUG
   252     bool alreadyThrowing = cx->isExceptionPending();
   253 #endif
   254     assertSameCompartment(cx, args);
   255     bool ok = impl(cx, args);
   256     if (ok) {
   257         assertSameCompartment(cx, args.rval());
   258         JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
   259     }
   260     return ok;
   261 }
   263 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
   264 MOZ_ALWAYS_INLINE bool
   265 CallJSNativeConstructor(JSContext *cx, Native native, const CallArgs &args)
   266 {
   267 #ifdef DEBUG
   268     RootedObject callee(cx, &args.callee());
   269 #endif
   271     JS_ASSERT(args.thisv().isMagic());
   272     if (!CallJSNative(cx, native, args))
   273         return false;
   275     /*
   276      * Native constructors must return non-primitive values on success.
   277      * Although it is legal, if a constructor returns the callee, there is a
   278      * 99.9999% chance it is a bug. If any valid code actually wants the
   279      * constructor to return the callee, the assertion can be removed or
   280      * (another) conjunct can be added to the antecedent.
   281      *
   282      * Exceptions:
   283      *
   284      * - Proxies are exceptions to both rules: they can return primitives and
   285      *   they allow content to return the callee.
   286      *
   287      * - CallOrConstructBoundFunction is an exception as well because we might
   288      *   have used bind on a proxy function.
   289      *
   290      * - new Iterator(x) is user-hookable; it returns x.__iterator__() which
   291      *   could be any object.
   292      *
   293      * - (new Object(Object)) returns the callee.
   294      */
   295     JS_ASSERT_IF(native != ProxyObject::callableClass_.construct &&
   296                  native != js::CallOrConstructBoundFunction &&
   297                  native != js::IteratorConstructor &&
   298                  (!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
   299                  !args.rval().isPrimitive() && callee != &args.rval().toObject());
   301     return true;
   302 }
   304 MOZ_ALWAYS_INLINE bool
   305 CallJSPropertyOp(JSContext *cx, PropertyOp op, HandleObject receiver, HandleId id, MutableHandleValue vp)
   306 {
   307     JS_CHECK_RECURSION(cx, return false);
   309     assertSameCompartment(cx, receiver, id, vp);
   310     bool ok = op(cx, receiver, id, vp);
   311     if (ok)
   312         assertSameCompartment(cx, vp);
   313     return ok;
   314 }
   316 MOZ_ALWAYS_INLINE bool
   317 CallJSPropertyOpSetter(JSContext *cx, StrictPropertyOp op, HandleObject obj, HandleId id,
   318                        bool strict, MutableHandleValue vp)
   319 {
   320     JS_CHECK_RECURSION(cx, return false);
   322     assertSameCompartment(cx, obj, id, vp);
   323     return op(cx, obj, id, strict, vp);
   324 }
   326 static inline bool
   327 CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id,
   328                        bool *succeeded)
   329 {
   330     JS_CHECK_RECURSION(cx, return false);
   332     assertSameCompartment(cx, receiver, id);
   333     return op(cx, receiver, id, succeeded);
   334 }
   336 inline bool
   337 CallSetter(JSContext *cx, HandleObject obj, HandleId id, StrictPropertyOp op, unsigned attrs,
   338            bool strict, MutableHandleValue vp)
   339 {
   340     if (attrs & JSPROP_SETTER) {
   341         RootedValue opv(cx, CastAsObjectJsval(op));
   342         return InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp);
   343     }
   345     if (attrs & JSPROP_GETTER)
   346         return js_ReportGetterOnlyAssignment(cx, strict);
   348     return CallJSPropertyOpSetter(cx, op, obj, id, strict, vp);
   349 }
   351 inline uintptr_t
   352 GetNativeStackLimit(ThreadSafeContext *cx)
   353 {
   354     StackKind kind;
   355     if (cx->isJSContext()) {
   356         kind = cx->asJSContext()->runningWithTrustedPrincipals()
   357                  ? StackForTrustedScript : StackForUntrustedScript;
   358     } else {
   359         // For other threads, we just use the trusted stack depth, since it's
   360         // unlikely that we'll be mixing trusted and untrusted code together.
   361         kind = StackForTrustedScript;
   362     }
   363     return cx->perThreadData->nativeStackLimit[kind];
   364 }
   366 inline LifoAlloc &
   367 ExclusiveContext::typeLifoAlloc()
   368 {
   369     return zone()->types.typeLifoAlloc;
   370 }
   372 }  /* namespace js */
   374 inline void
   375 JSContext::setPendingException(js::Value v)
   376 {
   377     JS_ASSERT(!IsPoisonedValue(v));
   378     this->throwing = true;
   379     this->unwrappedException_ = v;
   380     // We don't use assertSameCompartment here to allow
   381     // js::SetPendingExceptionCrossContext to work.
   382     JS_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
   383 }
   385 inline void
   386 JSContext::setDefaultCompartmentObject(JSObject *obj)
   387 {
   388     JS_ASSERT(!options().noDefaultCompartmentObject());
   389     defaultCompartmentObject_ = obj;
   390 }
   392 inline void
   393 JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj)
   394 {
   395     if (!options().noDefaultCompartmentObject() &&
   396         !defaultCompartmentObject_)
   397     {
   398         setDefaultCompartmentObject(obj);
   399     }
   400 }
   402 inline void
   403 js::ExclusiveContext::enterCompartment(JSCompartment *c)
   404 {
   405     enterCompartmentDepth_++;
   406     c->enter();
   407     setCompartment(c);
   408 }
   410 inline void
   411 js::ExclusiveContext::enterNullCompartment()
   412 {
   413     enterCompartmentDepth_++;
   414     setCompartment(nullptr);
   415 }
   417 inline void
   418 js::ExclusiveContext::leaveCompartment(JSCompartment *oldCompartment)
   419 {
   420     JS_ASSERT(hasEnteredCompartment());
   421     enterCompartmentDepth_--;
   423     // Only call leave() after we've setCompartment()-ed away from the current
   424     // compartment.
   425     JSCompartment *startingCompartment = compartment_;
   426     setCompartment(oldCompartment);
   427     if (startingCompartment)
   428         startingCompartment->leave();
   429 }
   431 inline void
   432 js::ExclusiveContext::setCompartment(JSCompartment *comp)
   433 {
   434     // ExclusiveContexts can only be in the atoms zone or in exclusive zones.
   435     JS_ASSERT_IF(!isJSContext() && !runtime_->isAtomsCompartment(comp),
   436                  comp->zone()->usedByExclusiveThread);
   438     // Normal JSContexts cannot enter exclusive zones.
   439     JS_ASSERT_IF(isJSContext() && comp,
   440                  !comp->zone()->usedByExclusiveThread);
   442     // Only one thread can be in the atoms compartment at a time.
   443     JS_ASSERT_IF(runtime_->isAtomsCompartment(comp),
   444                  runtime_->currentThreadHasExclusiveAccess());
   446     // Make sure that the atoms compartment has its own zone.
   447     JS_ASSERT_IF(comp && !runtime_->isAtomsCompartment(comp),
   448                  !runtime_->isAtomsZone(comp->zone()));
   450     // Both the current and the new compartment should be properly marked as
   451     // entered at this point.
   452     JS_ASSERT_IF(compartment_, compartment_->hasBeenEntered());
   453     JS_ASSERT_IF(comp, comp->hasBeenEntered());
   455     compartment_ = comp;
   456     zone_ = comp ? comp->zone() : nullptr;
   457     allocator_ = zone_ ? &zone_->allocator : nullptr;
   458 }
   460 inline JSScript *
   461 JSContext::currentScript(jsbytecode **ppc,
   462                          MaybeAllowCrossCompartment allowCrossCompartment) const
   463 {
   464     if (ppc)
   465         *ppc = nullptr;
   467     js::Activation *act = mainThread().activation();
   468     while (act && (act->cx() != this || (act->isJit() && !act->asJit()->isActive())))
   469         act = act->prev();
   471     if (!act)
   472         return nullptr;
   474     JS_ASSERT(act->cx() == this);
   476 #ifdef JS_ION
   477     if (act->isJit()) {
   478         JSScript *script = nullptr;
   479         js::jit::GetPcScript(const_cast<JSContext *>(this), &script, ppc);
   480         if (!allowCrossCompartment && script->compartment() != compartment())
   481             return nullptr;
   482         return script;
   483     }
   485     if (act->isAsmJS())
   486         return nullptr;
   487 #endif
   489     JS_ASSERT(act->isInterpreter());
   491     js::InterpreterFrame *fp = act->asInterpreter()->current();
   492     JS_ASSERT(!fp->runningInJit());
   494     JSScript *script = fp->script();
   495     if (!allowCrossCompartment && script->compartment() != compartment())
   496         return nullptr;
   498     if (ppc) {
   499         *ppc = act->asInterpreter()->regs().pc;
   500         JS_ASSERT(script->containsPC(*ppc));
   501     }
   502     return script;
   503 }
   505 template <JSThreadSafeNative threadSafeNative>
   506 inline bool
   507 JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp)
   508 {
   509     return threadSafeNative(cx, argc, vp);
   510 }
   512 template <JSThreadSafeNative threadSafeNative>
   513 inline bool
   514 JSParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp)
   515 {
   516     return threadSafeNative(cx, argc, vp);
   517 }
   519 /* static */ inline JSContext *
   520 js::ExecutionModeTraits<js::SequentialExecution>::toContextType(ExclusiveContext *cx)
   521 {
   522     return cx->asJSContext();
   523 }
   525 #endif /* jscntxtinlines_h */

mercurial