NS_IMETHODIMP nsJSCID::HasInstance(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject * /* unused */, HandleValue val, bool* bp, bool* _retval) { *bp = false; nsresult rv = NS_OK; if (val.isObject()) { // we have a JSObject RootedObject obj(cx, &val.toObject()); MOZ_ASSERT(obj, "when is an object not an object?"); // is this really a native xpcom object with a wrapper? nsIClassInfo* ci = nullptr; obj = FindObjectForHasInstance(cx, obj); if (!obj || !IS_WN_REFLECTOR(obj)) return rv; if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) ci = other_wrapper->GetClassInfo(); // We consider CID equality to be the thing that matters here. // This is perhaps debatable. if (ci) { nsID cid; if (NS_SUCCEEDED(ci->GetClassIDNoAlloc(&cid))) *bp = cid.Equals(mDetails->ID()); } } return rv; }
static bool CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp) { if (selfHostedValue.isObject()) { RootedObject selfHostedObject(cx, &selfHostedValue.toObject()); JSObject *clone = CloneObject(cx, selfHostedObject); if (!clone) return false; vp.setObject(*clone); } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) { // Nothing to do here: these are represented inline in the value. vp.set(selfHostedValue); } else if (selfHostedValue.isString()) { if (!selfHostedValue.toString()->isFlat()) MOZ_CRASH(); JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat(); JSString *clone = CloneString(cx, selfHostedString); if (!clone) return false; vp.setString(clone); } else { MOZ_CRASH("Self-hosting CloneValue can't clone given value."); } return true; }
/* ES6 draft rc3 7.2.8. */ bool js::IsRegExp(JSContext* cx, HandleValue value, bool* result) { /* Step 1. */ if (!value.isObject()) { *result = false; return true; } RootedObject obj(cx, &value.toObject()); /* Steps 2-3. */ RootedValue isRegExp(cx); RootedId matchId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().match)); if (!GetProperty(cx, obj, obj, matchId, &isRegExp)) return false; /* Step 4. */ if (!isRegExp.isUndefined()) { *result = ToBoolean(isRegExp); return true; } /* Steps 5-6. */ ESClassValue cls; if (!GetClassOfValue(cx, value, &cls)) return false; *result = cls == ESClass_RegExp; return true; }
bool js::GeneratorThrowOrClose(JSContext *cx, AbstractFramePtr frame, Handle<GeneratorObject*> genObj, HandleValue arg, uint32_t resumeKind) { if (resumeKind == GeneratorObject::THROW) { cx->setPendingException(arg); genObj->setRunning(); } else { MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE); if (genObj->is<StarGeneratorObject>()) { // Store the return value in the frame's CallObject so that we can // return it after executing finally blocks (and potentially // yielding again). MOZ_ASSERT(arg.isObject()); CallObject &callObj = frame.callObj(); Shape *shape = callObj.lookup(cx, cx->names().dotGenRVal); callObj.setSlot(shape->slot(), arg); } else { MOZ_ASSERT(arg.isUndefined()); } cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING)); genObj->setClosing(); } return false; }
NS_IMETHODIMP nsJSCID::HasInstance(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject * /* unused */, HandleValue val, bool* bp, bool* _retval) { *bp = false; if (!val.isObject()) return NS_OK; RootedObject obj(cx, &val.toObject()); // is this really a native xpcom object with a wrapper? RootedObject target(cx); nsresult rv = FindObjectForHasInstance(cx, obj, &target); if (NS_WARN_IF(NS_FAILED(rv))) return rv; if (!target || !IS_WN_REFLECTOR(target)) return NS_OK; if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(target)) { if (nsIClassInfo* ci = other_wrapper->GetClassInfo()) { // We consider CID equality to be the thing that matters here. // This is perhaps debatable. nsID cid; if (NS_SUCCEEDED(ci->GetClassIDNoAlloc(&cid))) *bp = cid.Equals(mDetails->ID()); } } return NS_OK; }
bool js::wasm::ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64) { if (!v.isObject()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL, "i64 JS value must be an object"); return false; } RootedObject obj(cx, &v.toObject()); int32_t* i32 = (int32_t*)i64; RootedValue val(cx); if (!JS_GetProperty(cx, obj, "low", &val)) return false; if (!ToInt32(cx, val, &i32[0])) return false; if (!JS_GetProperty(cx, obj, "high", &val)) return false; if (!ToInt32(cx, val, &i32[1])) return false; return true; }
static MOZ_ALWAYS_INLINE bool SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj, HandleObject key, HandleValue value) { ObjectValueMap* map = mapObj->getMap(); if (!map) { auto newMap = cx->make_unique<ObjectValueMap>(cx, mapObj.get()); if (!newMap) return false; if (!newMap->init()) { JS_ReportOutOfMemory(cx); return false; } map = newMap.release(); mapObj->setPrivate(map); } // Preserve wrapped native keys to prevent wrapper optimization. if (!TryPreserveReflector(cx, key)) return false; if (JSWeakmapKeyDelegateOp op = key->getClass()->extWeakmapKeyDelegateOp()) { RootedObject delegate(cx, op(key)); if (delegate && !TryPreserveReflector(cx, delegate)) return false; } MOZ_ASSERT(key->compartment() == mapObj->compartment()); MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment()); if (!map->put(key, value)) { JS_ReportOutOfMemory(cx); return false; } return true; }
static bool CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp) { if (selfHostedValue.isObject()) { RootedNativeObject selfHostedObject(cx, &selfHostedValue.toObject().as<NativeObject>()); JSObject *clone = CloneObject(cx, selfHostedObject); if (!clone) return false; vp.setObject(*clone); } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) { // Nothing to do here: these are represented inline in the value. vp.set(selfHostedValue); } else if (selfHostedValue.isString()) { if (!selfHostedValue.toString()->isFlat()) MOZ_CRASH(); JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat(); JSString *clone = CloneString(cx, selfHostedString); if (!clone) return false; vp.setString(clone); } else if (selfHostedValue.isSymbol()) { // Well-known symbols are shared. mozilla::DebugOnly<JS::Symbol *> sym = selfHostedValue.toSymbol(); MOZ_ASSERT(sym->isWellKnownSymbol()); MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym); vp.set(selfHostedValue); } else { MOZ_CRASH("Self-hosting CloneValue can't clone given value."); } return true; }
bool js::IsArrayBuffer(HandleValue v) { return v.isObject() && (v.toObject().is<ArrayBufferObject>() || v.toObject().is<SharedArrayBufferObject>()); }
MOZ_ALWAYS_INLINE bool Proxy::getInternal(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id, MutableHandleValue vp) { MOZ_ASSERT_IF(receiver.isObject(), !IsWindow(&receiver.toObject())); if (!CheckRecursionLimit(cx)) return false; const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler(); vp.setUndefined(); // default result if we refuse to perform this action AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true); if (!policy.allowed()) return policy.returnValue(); if (handler->hasPrototype()) { bool own; if (!handler->hasOwn(cx, proxy, id, &own)) return false; if (!own) { RootedObject proto(cx); if (!GetPrototype(cx, proxy, &proto)) return false; if (!proto) return true; return GetProperty(cx, proto, receiver, id, vp); } } return handler->get(cx, proxy, receiver, id, vp); }
/* * We can reify non-escaping iterator objects instead of having to wrap them. This * allows fast iteration over objects across a compartment boundary. */ static bool CanReify(HandleValue vp) { JSObject *obj; return vp.isObject() && (obj = &vp.toObject())->isPropertyIterator() && (obj->asPropertyIterator().getNativeIterator()->flags & JSITER_ENUMERATE); }
js::ToBooleanSlow(HandleValue v) { if (v.isString()) return v.toString()->length() != 0; JS_ASSERT(v.isObject()); return !EmulatesUndefined(&v.toObject()); }
bool CrossCompartmentWrapper::finalizeInBackground(HandleValue priv) { if (!priv.isObject()) return true; /* * Make the 'background-finalized-ness' of the wrapper the same as the * wrapped object, to allow transplanting between them. */ return IsBackgroundFinalized(priv.toObject().getAllocKind()); }
Node::Node(HandleValue value) { if (value.isObject()) construct(&value.toObject()); else if (value.isString()) construct(value.toString()); else if (value.isSymbol()) construct(value.toSymbol()); else construct<void>(nullptr); }
static bool CheckArgCompartment(JSContext *cx, JSObject *obj, HandleValue v, const char *methodname, const char *propname) { if (v.isObject() && v.toObject().compartment() != obj->compartment()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_COMPARTMENT_MISMATCH, methodname, propname); return false; } return true; }
static bool GetSharedTypedArray(JSContext* cx, HandleValue v, MutableHandle<SharedTypedArrayObject*> viewp) { if (!v.isObject()) return ReportBadArrayType(cx); if (!v.toObject().is<SharedTypedArrayObject>()) return ReportBadArrayType(cx); viewp.set(&v.toObject().as<SharedTypedArrayObject>()); return true; }
static bool TestProtoSetterThis(HandleValue v) { if (v.isNullOrUndefined()) return false; /* These will work as if on a boxed primitive; dumb, but whatever. */ if (!v.isObject()) return true; /* Otherwise, only accept non-proxies. */ return !v.toObject().is<ProxyObject>(); }
bool js::IsVectorObject(HandleValue v) { if (!v.isObject()) return false; JSObject &obj = v.toObject(); if (!obj.is<TypedObject>()) return false; TypeDescr &typeRepr = obj.as<TypedObject>().typeDescr(); if (typeRepr.kind() != type::X4) return false; return typeRepr.as<X4TypeDescr>().type() == V::type; }
static bool CheckVectorObject(HandleValue v, SimdType expectedType) { if (!v.isObject()) return false; JSObject& obj = v.toObject(); if (!obj.is<TypedObject>()) return false; TypeDescr& typeRepr = obj.as<TypedObject>().typeDescr(); if (typeRepr.kind() != type::Simd) return false; return typeRepr.as<SimdTypeDescr>().type() == expectedType; }
bool JS::detail::CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) { HandleValue thisv = args.thisv(); MOZ_ASSERT(!test(thisv)); if (thisv.isObject()) { JSObject &thisObj = args.thisv().toObject(); if (thisObj.is<ProxyObject>()) return Proxy::nativeCall(cx, test, impl, args); } ReportIncompatible(cx, args); return false; }
bool AccessCheck::checkPassToPrivilegedCode(JSContext* cx, HandleObject wrapper, HandleValue v) { // Primitives are fine. if (!v.isObject()) return true; RootedObject obj(cx, &v.toObject()); // Non-wrappers are fine. if (!js::IsWrapper(obj)) return true; // CPOWs use COWs (in the unprivileged junk scope) for all child->parent // references. Without this test, the child process wouldn't be able to // pass any objects at all to CPOWs. if (mozilla::jsipc::IsWrappedCPOW(obj) && js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(xpc::UnprivilegedJunkScope()) && XRE_IsParentProcess()) { return true; } // COWs are fine to pass to chrome if and only if they have __exposedProps__, // since presumably content should never have a reason to pass an opaque // object back to chrome. if (AccessCheck::isChrome(js::UncheckedUnwrap(wrapper)) && WrapperFactory::IsCOW(obj)) { RootedObject target(cx, js::UncheckedUnwrap(obj)); JSAutoCompartment ac(cx, target); RootedId id(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)); bool found = false; if (!JS_HasPropertyById(cx, target, id, &found)) return false; if (found) return true; } // Same-origin wrappers are fine. if (AccessCheck::wrapperSubsumes(obj)) return true; // Badness. JS_ReportError(cx, "Permission denied to pass object to privileged code"); return false; }
bool WrapperOwner::DOMQI(JSContext* cx, JS::HandleObject proxy, JS::CallArgs& args) { // Someone's calling us, handle nsISupports specially to avoid unnecessary // CPOW traffic. HandleValue id = args[0]; if (id.isObject()) { RootedObject idobj(cx, &id.toObject()); nsCOMPtr<nsIJSID> jsid; nsresult rv = UnwrapArg<nsIJSID>(cx, idobj, getter_AddRefs(jsid)); if (NS_SUCCEEDED(rv)) { MOZ_ASSERT(jsid, "bad wrapJS"); const nsID* idptr = jsid->GetID(); if (idptr->Equals(NS_GET_IID(nsISupports))) { args.rval().set(args.thisv()); return true; } // Webidl-implemented DOM objects never have nsIClassInfo. if (idptr->Equals(NS_GET_IID(nsIClassInfo))) return Throw(cx, NS_ERROR_NO_INTERFACE); } } // It wasn't nsISupports, call into the other process to do the QI for us // (since we don't know what other interfaces our object supports). Note // that we have to use JS_GetPropertyDescriptor here to avoid infinite // recursion back into CPOWDOMQI via WrapperOwner::get(). // We could stash the actual QI function on our own function object to avoid // if we're called multiple times, but since we're transient, there's no // point right now. JS::Rooted<PropertyDescriptor> propDesc(cx); if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc)) return false; if (!propDesc.value().isObject()) { MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node"); return Throw(cx, NS_ERROR_UNEXPECTED); } return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval()); }
bool CreateObjectIn(JSContext *cx, HandleValue vobj, CreateObjectInOptions &options, MutableHandleValue rval) { if (!vobj.isObject()) { JS_ReportError(cx, "Expected an object as the target scope"); return false; } RootedObject scope(cx, js::CheckedUnwrap(&vobj.toObject())); if (!scope) { JS_ReportError(cx, "Permission denied to create object in the target scope"); return false; } bool define = !JSID_IS_VOID(options.defineAs); if (define && js::IsScriptedProxy(scope)) { JS_ReportError(cx, "Defining property on proxy object is not allowed"); return false; } RootedObject obj(cx); { JSAutoCompartment ac(cx, scope); obj = JS_NewObject(cx, nullptr, JS::NullPtr(), scope); if (!obj) return false; if (define) { if (!JS_DefinePropertyById(cx, scope, options.defineAs, obj, JSPROP_ENUMERATE, JS_PropertyStub, JS_StrictPropertyStub)) return false; } } rval.setObject(*obj); if (!WrapperFactory::WaiveXrayAndWrap(cx, rval)) return false; return true; }
static bool GetDataProperty(JSContext *cx, HandleValue objVal, HandlePropertyName field, MutableHandleValue v) { if (!objVal.isObject()) return LinkFail(cx, "accessing property of non-object"); Rooted<JSPropertyDescriptor> desc(cx); RootedObject obj(cx, &objVal.toObject()); RootedId id(cx, NameToId(field)); if (!JS_GetPropertyDescriptorById(cx, obj, id, 0, &desc)) return false; if (!desc.object()) return LinkFail(cx, "property not present on object"); if (desc.hasGetterOrSetterObject()) return LinkFail(cx, "property is not a data property"); v.set(desc.value()); return true; }
bool js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> genObj, HandleValue arg, uint32_t resumeKind) { if (resumeKind == GeneratorObject::THROW) { cx->setPendingException(arg); genObj->setRunning(); } else { MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE); if (genObj->is<StarGeneratorObject>()) { MOZ_ASSERT(arg.isObject()); frame.setReturnValue(arg); } else { MOZ_ASSERT(arg.isUndefined()); } cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING)); genObj->setClosing(); } return false; }
MOZ_ALWAYS_INLINE bool Proxy::setInternal(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, ObjectOpResult& result) { MOZ_ASSERT_IF(receiver.isObject(), !IsWindow(&receiver.toObject())); if (!CheckRecursionLimit(cx)) return false; const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler(); AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true); if (!policy.allowed()) { if (!policy.returnValue()) return false; return result.succeed(); } // Special case. See the comment on BaseProxyHandler::mHasPrototype. if (handler->hasPrototype()) return handler->BaseProxyHandler::set(cx, proxy, id, v, receiver, result); return handler->set(cx, proxy, id, v, receiver, result); }
MOZ_ALWAYS_INLINE bool SetWeakMapEntryInternal(JSContext *cx, Handle<WeakMapObject*> mapObj, HandleObject key, HandleValue value) { ObjectValueMap *map = mapObj->getMap(); if (!map) { map = cx->new_<ObjectValueMap>(cx, mapObj.get()); if (!map) return false; if (!map->init()) { js_delete(map); JS_ReportOutOfMemory(cx); return false; } mapObj->setPrivate(map); } // Preserve wrapped native keys to prevent wrapper optimization. if (!TryPreserveReflector(cx, key)) return false; if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) { RootedObject delegate(cx, op(key)); if (delegate && !TryPreserveReflector(cx, delegate)) return false; } JS_ASSERT(key->compartment() == mapObj->compartment()); JS_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment()); if (!map->put(key, value)) { JS_ReportOutOfMemory(cx); return false; } WeakMapPostWriteBarrier(cx->runtime(), map, key.get()); return true; }
bool js::DirectEvalStringFromIon(JSContext *cx, HandleObject scopeobj, HandleScript callerScript, HandleValue thisValue, HandleString str, jsbytecode *pc, MutableHandleValue vp) { AssertInnerizedScopeChain(cx, *scopeobj); Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global()); if (!GlobalObject::isRuntimeCodeGenEnabled(cx, scopeObjGlobal)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL); return false; } // ES5 15.1.2.1 steps 2-8. unsigned staticLevel = callerScript->staticLevel() + 1; Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx)); if (!flatStr) return false; EvalJSONResult ejr = TryEvalJSON(cx, callerScript, flatStr, vp); if (ejr != EvalJSON_NotJSON) return ejr == EvalJSON_Success; EvalScriptGuard esg(cx); esg.lookupInEvalCache(flatStr, callerScript, pc); if (!esg.foundScript()) { RootedScript maybeScript(cx); const char *filename; unsigned lineno; JSPrincipals *originPrincipals; uint32_t pcOffset; DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset, &originPrincipals, CALLED_FROM_JSOP_EVAL); const char *introducerFilename = filename; if (maybeScript && maybeScript->scriptSource()->introducerFilename()) introducerFilename = maybeScript->scriptSource()->introducerFilename(); CompileOptions options(cx); options.setFileAndLine(filename, 1) .setCompileAndGo(true) .setForEval(true) .setNoScriptRval(false) .setOriginPrincipals(originPrincipals) .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset); AutoStableStringChars flatChars(cx); if (!flatChars.initTwoByte(cx, flatStr)) return false; const char16_t *chars = flatChars.twoByteRange().start().get(); SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; SourceBufferHolder srcBuf(chars, flatStr->length(), ownership); JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), scopeobj, callerScript, options, srcBuf, flatStr, staticLevel); if (!compiled) return false; esg.setNewScript(compiled); } // Primitive 'this' values should have been filtered out by Ion. If boxed, // the calling frame cannot be updated to store the new object. JS_ASSERT(thisValue.isObject() || thisValue.isUndefined() || thisValue.isNull()); return ExecuteKernel(cx, esg.script(), *scopeobj, thisValue, ExecuteType(DIRECT_EVAL), NullFramePtr() /* evalInFrame */, vp.address()); }
MOZ_ALWAYS_INLINE bool IsBoolean(HandleValue v) { return v.isBoolean() || (v.isObject() && v.toObject().is<BooleanObject>()); }
/* static */ bool ImportEntryObject::isInstance(HandleValue value) { return value.isObject() && value.toObject().is<ImportEntryObject>(); }