void Promise::Then(JSContext* aCx, // aCalleeGlobal may not be in the compartment of aCx, when called over // Xrays. JS::Handle<JSObject*> aCalleeGlobal, AnyCallback* aResolveCallback, AnyCallback* aRejectCallback, JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) { NS_ASSERT_OWNINGTHREAD(Promise); // Let's hope this does the right thing with Xrays... Ensure everything is // just in the caller compartment; that ought to do the trick. In theory we // should consider aCalleeGlobal, but in practice our only caller is // DOMRequest::Then, which is not working with a Promise subclass, so things // should be OK. JS::Rooted<JSObject*> promise(aCx, PromiseObj()); if (!JS_WrapObject(aCx, &promise)) { aRv.NoteJSContextException(aCx); return; } JS::Rooted<JSObject*> resolveCallback(aCx); if (aResolveCallback) { resolveCallback = aResolveCallback->CallbackOrNull(); if (!JS_WrapObject(aCx, &resolveCallback)) { aRv.NoteJSContextException(aCx); return; } } JS::Rooted<JSObject*> rejectCallback(aCx); if (aRejectCallback) { rejectCallback = aRejectCallback->CallbackOrNull(); if (!JS_WrapObject(aCx, &rejectCallback)) { aRv.NoteJSContextException(aCx); return; } } JS::Rooted<JSObject*> retval(aCx); retval = JS::CallOriginalPromiseThen(aCx, promise, resolveCallback, rejectCallback); if (!retval) { aRv.NoteJSContextException(aCx); return; } aRetval.setObject(*retval); }
bool WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleObject argObj) { MOZ_ASSERT(argObj); RootedObject obj(cx, js::UncheckedUnwrap(argObj)); MOZ_ASSERT(!js::IsInnerObject(obj)); if (js::IsObjectInContextCompartment(obj, cx)) { argObj.set(obj); return true; } // Even though waivers have no effect on access by scopes that don't subsume // the underlying object, good defense-in-depth dictates that we should avoid // handing out waivers to callers that can't use them. The transitive waiving // machinery unconditionally calls WaiveXrayAndWrap on return values from // waived functions, even though the return value might be not be same-origin // with the function. So if we find ourselves trying to create a waiver for // |cx|, we should check whether the caller has any business with waivers // to things in |obj|'s compartment. JSCompartment *target = js::GetContextCompartment(cx); JSCompartment *origin = js::GetObjectCompartment(obj); obj = AccessCheck::subsumes(target, origin) ? WaiveXray(cx, obj) : obj; if (!obj) return false; if (!JS_WrapObject(cx, &obj)) return false; argObj.set(obj); return true; }
void WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName, JS::Handle<JSObject*> aPrototype, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); aResult.set(nullptr); JS::Rooted<JS::Value> protoVal(aCx); protoVal.setObjectOrNull(aPrototype); JS::Rooted<JSObject*> sandbox(aCx, SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox, protoVal)); if (!sandbox) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } if (!JS_WrapObject(aCx, &sandbox)) { aRv.NoteJSContextException(aCx); return; } aResult.set(sandbox); }
NS_IMETHODIMP xpcJSWeakReference::Get(JSContext* aCx, JS::Value* aRetval) { *aRetval = JSVAL_NULL; if (!mWrappedJSObject) { return NS_OK; } nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryReferent(mWrappedJSObject); if (!wrappedObj) { return NS_OK; } JSObject *obj; wrappedObj->GetJSObject(&obj); if (!obj) { return NS_OK; } // Most users of XPCWrappedJS don't need to worry about // re-wrapping because things are implicitly rewrapped by // xpcconvert. However, because we're doing this directly // through the native call context, we need to call // JS_WrapObject(). if (!JS_WrapObject(aCx, &obj)) { return NS_ERROR_FAILURE; } *aRetval = OBJECT_TO_JSVAL(obj); return NS_OK; }
static bool bootstrap_coverage(GjsCoverage *coverage) { GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage); JSContext *context = (JSContext *) gjs_context_get_native_context(priv->context); JSAutoRequest ar(context); JSObject *debuggee = gjs_get_import_global(context); JS::RootedObject debugger_compartment(context, gjs_create_global_object(context)); { JSAutoCompartment compartment(context, debugger_compartment); JS::RootedObject debuggeeWrapper(context, debuggee); if (!JS_WrapObject(context, &debuggeeWrapper)) return false; JS::RootedValue debuggeeWrapperValue(context, JS::ObjectValue(*debuggeeWrapper)); if (!JS_SetProperty(context, debugger_compartment, "debuggee", debuggeeWrapperValue) || !gjs_define_global_properties(context, debugger_compartment, "coverage")) return false; /* Add a tracer, as suggested by jdm on #jsapi */ JS_AddExtraGCRootsTracer(context, coverage_tracer, coverage); priv->compartment = debugger_compartment; } return true; }
static JSObject* GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, uint32_t aData, void* aClosure) { WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); workerPrivate->AssertIsOnWorkerThread(); if (aTag != WORKER_DATA_STORES_TAG) { MOZ_ASSERT(false, "aTag must be WORKER_DATA_STORES_TAG!"); return nullptr; } NS_ASSERTION(!aData, "aData should be empty"); // Read the holder from the buffer, which points to the data store. nsMainThreadPtrHolder<DataStore>* dataStoreholder; if (!JS_ReadBytes(aReader, &dataStoreholder, sizeof(dataStoreholder))) { MOZ_ASSERT(false, "cannot read bytes for dataStoreholder!"); return nullptr; } // Protect workerStoreObj from moving GC during ~nsRefPtr. JS::Rooted<JSObject*> workerStoreObj(aCx, nullptr); { nsRefPtr<WorkerDataStore> workerStore = new WorkerDataStore(workerPrivate->GlobalScope()); nsMainThreadPtrHandle<DataStore> backingStore(dataStoreholder); // When we're on the worker thread, prepare a DataStoreChangeEventProxy. nsRefPtr<DataStoreChangeEventProxy> eventProxy = new DataStoreChangeEventProxy(workerPrivate, workerStore); // Add the DataStoreChangeEventProxy as an event listener on the main thread. nsRefPtr<DataStoreAddEventListenerRunnable> runnable = new DataStoreAddEventListenerRunnable(workerPrivate, backingStore, eventProxy); runnable->Dispatch(aCx); // Point WorkerDataStore to DataStore. workerStore->SetBackingDataStore(backingStore); JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); if (!global) { MOZ_ASSERT(false, "cannot get global!"); } else { workerStoreObj = workerStore->WrapObject(aCx); if (!JS_WrapObject(aCx, &workerStoreObj)) { MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!"); workerStoreObj = nullptr; } } } return workerStoreObj; }
static JSObject* wrap(JSContext* cx, JS::HandleObject toWrap, JS::HandleObject target) { JSAutoCompartment ac(cx, target); JS::RootedObject wrapper(cx, toWrap); if (!JS_WrapObject(cx, &wrapper)) return nullptr; return wrapper; }
static JSObject * wrap(JSContext *cx, JS::HandleObject toWrap, JS::HandleObject target) { JSAutoCompartment ac(cx, target); JS::RootedObject wrapper(cx, toWrap); if (!JS_WrapObject(cx, wrapper.address())) return NULL; return wrapper; }
static JSObject * wrap(JSContext *cx, JSObject *toWrap, JSObject *target) { JSAutoEnterCompartment ac; if (!ac.enter(cx, target)) return NULL; JSObject *wrapper = toWrap; if (!JS_WrapObject(cx, &wrapper)) return NULL; return wrapper; }
JSObject * WrapperFactory::WaiveXray(JSContext *cx, JSObject *obj) { obj = UnwrapObject(obj); // We have to make sure that if we're wrapping an outer window, that // the .wrappedJSObject also wraps the outer window. obj = GetCurrentOuter(cx, obj); { // See if we already have a waiver wrapper for this object. CompartmentPrivate *priv = (CompartmentPrivate *)JS_GetCompartmentPrivate(js::GetObjectCompartment(obj)); JSObject *wobj = nsnull; if (priv && priv->waiverWrapperMap) { wobj = priv->waiverWrapperMap->Find(obj); xpc_UnmarkGrayObject(wobj); } // No wrapper yet, make one. if (!wobj) { JSObject *proto = js::GetObjectProto(obj); if (proto && !(proto = WaiveXray(cx, proto))) return nsnull; JSAutoEnterCompartment ac; if (!ac.enter(cx, obj) || !JS_WrapObject(cx, &proto)) return nsnull; wobj = Wrapper::New(cx, obj, proto, JS_GetGlobalForObject(cx, obj), &WaiveXrayWrapperWrapper); if (!wobj) return nsnull; // Add the new wrapper so we find it next time. if (priv) { if (!priv->waiverWrapperMap) { priv->waiverWrapperMap = JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE); if (!priv->waiverWrapperMap) return nsnull; } if (!priv->waiverWrapperMap->Add(obj, wobj)) return nsnull; } } obj = wobj; } return obj; }
NS_IMETHODIMP xpcJSWeakReference::Get(JSContext* aCx, JS::Value* aRetval) { *aRetval = JSVAL_NULL; if (!mReferent) { return NS_OK; } nsCOMPtr<nsISupports> supports = do_QueryReferent(mReferent); if (!supports) { return NS_OK; } nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(supports); if (!wrappedObj) { // We have a generic XPCOM object that supports weak references here. // Wrap it and pass it out. JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); return nsContentUtils::WrapNative(aCx, global, supports, &NS_GET_IID(nsISupports), aRetval); } JS::RootedObject obj(aCx, wrappedObj->GetJSObject()); if (!obj) { return NS_OK; } // Most users of XPCWrappedJS don't need to worry about // re-wrapping because things are implicitly rewrapped by // xpcconvert. However, because we're doing this directly // through the native call context, we need to call // JS_WrapObject(). if (!JS_WrapObject(aCx, obj.address())) { return NS_ERROR_FAILURE; } *aRetval = OBJECT_TO_JSVAL(obj); return NS_OK; }
JSObject* newCCW(JS::HandleObject sourceZone, JS::HandleObject destZone) { /* * Now ensure that this zone will be swept first by adding a cross * compartment wrapper to a new objct in the same zone as the * delegate obejct. */ JS::RootedObject object(cx); { JSAutoCompartment ac(cx, destZone); object = JS_NewPlainObject(cx); if (!object) return nullptr; } { JSAutoCompartment ac(cx, sourceZone); if (!JS_WrapObject(cx, &object)) return nullptr; } return object; }
// static already_AddRefed<Promise> Promise::All(const GlobalObject& aGlobal, const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global; global = do_QueryInterface(aGlobal.GetAsSupports()); if (!global) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } JSContext* cx = aGlobal.Context(); JS::AutoObjectVector promises(cx); if (!promises.reserve(aPromiseList.Length())) { aRv.NoteJSContextException(cx); return nullptr; } for (auto& promise : aPromiseList) { JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj()); // Just in case, make sure these are all in the context compartment. if (!JS_WrapObject(cx, &promiseObj)) { aRv.NoteJSContextException(cx); return nullptr; } promises.infallibleAppend(promiseObj); } JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises)); if (!result) { aRv.NoteJSContextException(cx); return nullptr; } return CreateFromExisting(global, result); }
nsresult nsXBLProtoImplMethod::InstallMember(JSContext* aCx, JSObject* aTargetClassObject) { NS_PRECONDITION(IsCompiled(), "Should not be installing an uncompiled method"); MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx)); JSObject* globalObject = JS_GetGlobalForObject(aCx, aTargetClassObject); JSObject* scopeObject = xpc::GetXBLScope(aCx, globalObject); // now we want to reevaluate our property using aContext and the script object for this window... if (mJSMethodObject) { nsDependentString name(mName); // First, make the function in the compartment of the scope object. JSAutoCompartment ac(aCx, scopeObject); JSObject * method = ::JS_CloneFunctionObject(aCx, mJSMethodObject, scopeObject); if (!method) { return NS_ERROR_OUT_OF_MEMORY; } // Then, enter the content compartment, wrap the method pointer, and define // the wrapped version on the class object. JSAutoCompartment ac2(aCx, aTargetClassObject); if (!JS_WrapObject(aCx, &method) || !::JS_DefineUCProperty(aCx, aTargetClassObject, static_cast<const jschar*>(mName), name.Length(), OBJECT_TO_JSVAL(method), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) { return NS_ERROR_OUT_OF_MEMORY; } } return NS_OK; }
JSObject * WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj) { // The caller is required to have already done a lookup. // NB: This implictly performs the assertions of GetXrayWaiver. MOZ_ASSERT(!GetXrayWaiver(obj)); XPCWrappedNativeScope *scope = GetObjectScope(obj); // Get a waiver for the proto. JSObject *proto; if (!js::GetObjectProto(cx, obj, &proto)) return nullptr; if (proto && !(proto = WaiveXray(cx, proto))) return nullptr; // Create the waiver. JSAutoCompartment ac(cx, obj); if (!JS_WrapObject(cx, &proto)) return nullptr; JSObject *waiver = Wrapper::New(cx, obj, proto, JS_GetGlobalForObject(cx, obj), &XrayWaiver); if (!waiver) return nullptr; // Add the new waiver to the map. It's important that we only ever have // one waiver for the lifetime of the target object. if (!scope->mWaiverWrapperMap) { scope->mWaiverWrapperMap = JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE); MOZ_ASSERT(scope->mWaiverWrapperMap); } if (!scope->mWaiverWrapperMap->Add(obj, waiver)) return nullptr; return waiver; }
nsresult nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement) { NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method"); if (!mJSMethodObject) { // Nothing to do here return NS_OK; } // Get the script context the same way // nsXBLProtoImpl::InstallImplementation does. nsIDocument* document = aBoundElement->OwnerDoc(); nsIScriptGlobalObject* global = document->GetScriptGlobalObject(); if (!global) { return NS_OK; } nsCOMPtr<nsIScriptContext> context = global->GetContext(); if (!context) { return NS_OK; } nsAutoMicroTask mt; JSContext* cx = context->GetNativeContext(); JSObject* globalObject = global->GetGlobalJSObject(); nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper; jsval v; nsresult rv = nsContentUtils::WrapNative(cx, globalObject, aBoundElement, &v, getter_AddRefs(wrapper)); NS_ENSURE_SUCCESS(rv, rv); // Use nsCxPusher to make sure we call ScriptEvaluated when we're done. // // Make sure to do this before entering the compartment, since pushing Push() // may call JS_SaveFrameChain(), which puts us back in an unentered state. nsCxPusher pusher; NS_ENSURE_STATE(pusher.Push(aBoundElement)); MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext()); JSObject* thisObject = JSVAL_TO_OBJECT(v); JSObject* scopeObject = xpc::GetXBLScope(cx, globalObject); JSAutoRequest ar(cx); JSAutoCompartment ac(cx, scopeObject); if (!JS_WrapObject(cx, &thisObject)) return NS_ERROR_OUT_OF_MEMORY; // Clone the function object, using thisObject as the parent so "this" is in // the scope chain of the resulting function (for backwards compat to the // days when this was an event handler). JSObject* method = ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject); if (!method) return NS_ERROR_OUT_OF_MEMORY; // Now call the method // Check whether it's OK to call the method. rv = nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx, method, thisObject); JSBool ok = JS_TRUE; if (NS_SUCCEEDED(rv)) { jsval retval; ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method), 0 /* argc */, nullptr /* argv */, &retval); } if (!ok) { // If a constructor or destructor threw an exception, it doesn't stop // anything else. We just report it. Note that we need to set aside the // frame chain here, since the constructor invocation is not related to // whatever is on the stack right now, really. JSBool saved = JS_SaveFrameChain(cx); JS_ReportPendingException(cx); if (saved) JS_RestoreFrameChain(cx); return NS_ERROR_FAILURE; } return NS_OK; }
// static JSObject* SimpleGlobalObject::Create(GlobalType globalType, JS::Handle<JS::Value> proto) { // We can't root our return value with our AutoJSAPI because the rooting // analysis thinks ~AutoJSAPI can GC. So we need to root in a scope outside // the lifetime of the AutoJSAPI. JS::Rooted<JSObject*> global(RootingCx()); { // Scope to ensure the AutoJSAPI destructor runs before we end up returning AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); JS::CompartmentOptions options; options.creationOptions() .setInvisibleToDebugger(true) // Put our SimpleGlobalObjects in the system zone, so we won't create // lots of zones for what are probably very short-lived // compartments. This should help them be GCed quicker and take up // less memory before they're GCed. .setZone(JS::SystemZone); if (NS_IsMainThread()) { nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create(); options.creationOptions().setTrace(xpc::TraceXPCGlobal); global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass), nsJSPrincipals::get(principal), options); } else { global = JS_NewGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass), nullptr, JS::DontFireOnNewGlobalHook, options); } if (!global) { jsapi.ClearException(); return nullptr; } JSAutoCompartment ac(cx, global); // It's important to create the nsIGlobalObject for our new global before we // start trying to wrap things like the prototype into its compartment, // because the wrap operation relies on the global having its // nsIGlobalObject already. RefPtr<SimpleGlobalObject> globalObject = new SimpleGlobalObject(global, globalType); // Pass on ownership of globalObject to |global|. JS_SetPrivate(global, globalObject.forget().take()); if (proto.isObjectOrNull()) { JS::Rooted<JSObject*> protoObj(cx, proto.toObjectOrNull()); if (!JS_WrapObject(cx, &protoObj)) { jsapi.ClearException(); return nullptr; } if (!JS_SplicePrototype(cx, global, protoObj)) { jsapi.ClearException(); return nullptr; } } else if (!proto.isUndefined()) { // Bogus proto. return nullptr; } JS_FireOnNewGlobalObject(cx, global); } return global; }
/* static */ bool WebIDLGlobalNameHash::DefineIfEnabled( JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId, JS::MutableHandle<JS::PropertyDescriptor> aDesc, bool* aFound) { MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!"); const WebIDLNameTableEntry* entry; { entry = GetEntry(JSID_TO_FLAT_STRING(aId)); } if (!entry) { *aFound = false; return true; } *aFound = true; ConstructorEnabled checkEnabledForScope = entry->mEnabled; // We do the enabled check on the current Realm of aCx, but for the // actual object we pass in the underlying object in the Xray case. That // way the callee can decide whether to allow access based on the caller // or the window being touched. // // Using aCx to represent the current Realm for CheckedUnwrapDynamic // purposes is OK here, because that's the Realm where we plan to do // our property-defining. JS::Rooted<JSObject*> global( aCx, js::CheckedUnwrapDynamic(aObj, aCx, /* stopAtWindowProxy = */ false)); if (!global) { return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR); } { // It's safe to pass "&global" here, because we've already unwrapped it, but // for general sanity better to not have debug code even having the // appearance of mutating things that opt code uses. #ifdef DEBUG JS::Rooted<JSObject*> temp(aCx, global); DebugOnly<nsGlobalWindowInner*> win; MOZ_ASSERT(NS_SUCCEEDED( UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &temp, win, aCx))); #endif } if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) { return true; } // The DOM constructor resolve machinery interacts with Xrays in tricky // ways, and there are some asymmetries that are important to understand. // // In the regular (non-Xray) case, we only want to resolve constructors // once (so that if they're deleted, they don't reappear). We do this by // stashing the constructor in a slot on the global, such that we can see // during resolve whether we've created it already. This is rather // memory-intensive, so we don't try to maintain these semantics when // manipulating a global over Xray (so the properties just re-resolve if // they've been deleted). // // Unfortunately, there's a bit of an impedance-mismatch between the Xray // and non-Xray machinery. The Xray machinery wants an API that returns a // JS::PropertyDescriptor, so that the resolve hook doesn't have to get // snared up with trying to define a property on the Xray holder. At the // same time, the DefineInterface callbacks are set up to define things // directly on the global. And re-jiggering them to return property // descriptors is tricky, because some DefineInterface callbacks define // multiple things (like the Image() alias for HTMLImageElement). // // So the setup is as-follows: // // * The resolve function takes a JS::PropertyDescriptor, but in the // non-Xray case, callees may define things directly on the global, and // set the value on the property descriptor to |undefined| to indicate // that there's nothing more for the caller to do. We assert against // this behavior in the Xray case. // // * We make sure that we do a non-Xray resolve first, so that all the // slots are set up. In the Xray case, this means unwrapping and doing // a non-Xray resolve before doing the Xray resolve. // // This all could use some grand refactoring, but for now we just limp // along. if (xpc::WrapperFactory::IsXrayWrapper(aObj)) { JS::Rooted<JSObject*> constructor(aCx); { JSAutoRealm ar(aCx, global); constructor = FindNamedConstructorForXray(aCx, aId, entry); } if (NS_WARN_IF(!constructor)) { return Throw(aCx, NS_ERROR_FAILURE); } if (!JS_WrapObject(aCx, &constructor)) { return Throw(aCx, NS_ERROR_FAILURE); } FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*constructor)); return true; } JS::Rooted<JSObject*> interfaceObject( aCx, GetPerInterfaceObjectHandle(aCx, entry->mConstructorId, entry->mCreate, /* aDefineOnGlobal = */ true)); if (NS_WARN_IF(!interfaceObject)) { return Throw(aCx, NS_ERROR_FAILURE); } // We've already defined the property. We indicate this to the caller // by filling a property descriptor with JS::UndefinedValue() as the // value. We still have to fill in a property descriptor, though, so // that the caller knows the property is in fact on this object. It // doesn't matter what we pass for the "readonly" argument here. FillPropertyDescriptor(aDesc, aObj, JS::UndefinedValue(), false); return true; }