Пример #1
0
static bool
args_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
             MutableHandleObject objp)
{
    objp.set(nullptr);

    Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>());

    unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
    if (JSID_IS_INT(id)) {
        uint32_t arg = uint32_t(JSID_TO_INT(id));
        if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
            return true;

        attrs |= JSPROP_ENUMERATE;
    } else if (JSID_IS_ATOM(id, cx->names().length)) {
        if (argsobj->hasOverriddenLength())
            return true;
    } else {
        if (!JSID_IS_ATOM(id, cx->names().callee))
            return true;

        if (argsobj->callee().isMagic(JS_OVERWRITTEN_CALLEE))
            return true;
    }

    if (!baseops::DefineGeneric(cx, argsobj, id, UndefinedHandleValue, ArgGetter, ArgSetter, attrs))
        return false;

    objp.set(argsobj);
    return true;
}
Пример #2
0
JS_NondeterministicGetWeakMapKeys(JSContext *cx, HandleObject objArg, MutableHandleObject ret)
{
    RootedObject obj(cx, objArg);
    obj = UncheckedUnwrap(obj);
    if (!obj || !obj->is<WeakMapObject>()) {
        ret.set(nullptr);
        return true;
    }
    RootedObject arr(cx, NewDenseEmptyArray(cx));
    if (!arr)
        return false;
    ObjectValueMap *map = obj->as<WeakMapObject>().getMap();
    if (map) {
        // Prevent GC from mutating the weakmap while iterating.
        AutoSuppressGC suppress(cx);
        for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
            RootedObject key(cx, r.front().key());
            if (!cx->compartment()->wrap(cx, &key))
                return false;
            if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
                return false;
        }
    }
    ret.set(arr);
    return true;
}
Пример #3
0
bool
JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj)
{
    // Ensure that we have entered a compartment.
    MOZ_ASSERT(cx->global());

    // If we have a cross-compartment wrapper, make sure that the cx isn't
    // associated with the self-hosting global. We don't want to create
    // wrappers for objects in other runtimes, which may be the case for the
    // self-hosting global.
    MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(cx->global()));
    MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(&obj->global()));

    // The object is already in the right compartment. Normally same-
    // compartment returns the object itself, however, windows are always
    // wrapped by a proxy, so we have to check for that case here manually.
    if (obj->compartment() == this) {
        obj.set(ToWindowProxyIfWindow(obj));
        return true;
    }

    // Note that if the object is same-compartment, but has been wrapped into a
    // different compartment, we need to unwrap it and return the bare same-
    // compartment object. Note again that windows are always wrapped by a
    // WindowProxy even when same-compartment so take care not to strip this
    // particular wrapper.
    RootedObject objectPassedToWrap(cx, obj);
    obj.set(UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true));
    if (obj->compartment() == this) {
        MOZ_ASSERT(!IsWindow(obj));
        return true;
    }

    // Invoke the prewrap callback. The prewrap callback is responsible for
    // doing similar reification as above, but can account for any additional
    // embedder requirements.
    //
    // We're a bit worried about infinite recursion here, so we do a check -
    // see bug 809295.
    auto preWrap = cx->runtime()->wrapObjectCallbacks->preWrap;
    if (!CheckSystemRecursionLimit(cx))
        return false;
    if (preWrap) {
        preWrap(cx, cx->global(), obj, objectPassedToWrap, obj);
        if (!obj)
            return false;
    }
    MOZ_ASSERT(!IsWindow(obj));

    return true;
}
Пример #4
0
static bool
CreateExportObject(JSContext* cx, Handle<WasmModuleObject*> moduleObj, const ExportMap& exportMap,
                   const ExportVector& exports, MutableHandleObject exportObj)
{
    MOZ_ASSERT(exportMap.exportNames.length() == exports.length());
    MOZ_ASSERT(exportMap.fieldNames.length() == exportMap.fieldsToExports.length());

    for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) {
        const char* fieldName = exportMap.fieldNames[fieldIndex].get();
        if (!*fieldName) {
            MOZ_ASSERT(!exportObj);
            uint32_t exportIndex = exportMap.fieldsToExports[fieldIndex];
            exportObj.set(NewExportedFunction(cx, moduleObj, exportMap, exportIndex));
            if (!exportObj)
                return false;
            break;
        }
    }

    Rooted<ValueVector> vals(cx, ValueVector(cx));
    for (size_t exportIndex = 0; exportIndex < exports.length(); exportIndex++) {
        JSFunction* fun = NewExportedFunction(cx, moduleObj, exportMap, exportIndex);
        if (!fun || !vals.append(ObjectValue(*fun)))
            return false;
    }

    if (!exportObj) {
        exportObj.set(JS_NewPlainObject(cx));
        if (!exportObj)
            return false;
    }

    for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) {
        const char* fieldName = exportMap.fieldNames[fieldIndex].get();
        if (!*fieldName)
            continue;

        JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName));
        if (!atom)
            return false;

        RootedId id(cx, AtomToId(atom));
        HandleValue val = vals[exportMap.fieldsToExports[fieldIndex]];
        if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
            return false;
    }

    return true;
}
Пример #5
0
/*
 * HasInstance hooks need to find an appropriate reflector in order to function
 * properly. There are two complexities that we need to handle:
 *
 * 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with
 *     system principal. The success of an instanceof check should not depend
 *     on which compartment an object comes from. At the same time, we want to
 *     make sure we don't unwrap important security wrappers.
 *     CheckedUnwrap does the right thing here.
 *
 * 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and
 *     sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true,
 *     one would expect |a instanceof nsIFoo| to return true as well, since
 *     instanceof is transitive up the prototype chain in ECMAScript. Moreover,
 *     there's chrome code that relies on this.
 *
 * This static method handles both complexities, returning either an XPCWN, a
 * DOM object, or null. The object may well be cross-compartment from |cx|.
 */
static nsresult
FindObjectForHasInstance(JSContext* cx, HandleObject objArg, MutableHandleObject target)
{
    RootedObject obj(cx, objArg), proto(cx);

    while (obj && !IS_WN_REFLECTOR(obj) &&
           !IsDOMObject(obj) && !mozilla::jsipc::IsCPOW(obj))
    {
        if (js::IsWrapper(obj)) {
            obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
            continue;
        }

        {
            JSAutoCompartment ac(cx, obj);
            if (!js::GetObjectProto(cx, obj, &proto))
                return NS_ERROR_FAILURE;
        }

        obj = proto;
    }

    target.set(obj);
    return NS_OK;
}
Пример #6
0
bool
JSCompartment::getTemplateLiteralObject(JSContext* cx, HandleArrayObject rawStrings,
                                        MutableHandleObject templateObj)
{
    if (TemplateRegistry::AddPtr p = templateLiteralMap_.lookupForAdd(rawStrings)) {
        templateObj.set(p->value());

        // The template object must have been frozen when it was added to the
        // registry.
        MOZ_ASSERT(!templateObj->nonProxyIsExtensible());
    } else {
        MOZ_ASSERT(templateObj->nonProxyIsExtensible());
        RootedValue rawValue(cx, ObjectValue(*rawStrings));
        if (!DefineDataProperty(cx, templateObj, cx->names().raw, rawValue, 0))
            return false;
        if (!FreezeObject(cx, rawStrings))
            return false;
        if (!FreezeObject(cx, templateObj))
            return false;

        if (!templateLiteralMap_.relookupOrAdd(p, rawStrings, templateObj))
            return false;
    }

    return true;
}
bool
OpaqueCrossCompartmentWrapper::getPrototype(JSContext* cx, HandleObject proxy,
                                            MutableHandleObject protop) const
{
    protop.set(nullptr);
    return true;
}
Пример #8
0
bool
ModuleNamespaceObject::ProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
                                                  MutableHandleObject protop) const
{
    protop.set(nullptr);
    return true;
}
Пример #9
0
static bool
proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
                     MutableHandleObject objp, MutableHandle<JS::PropertyResult> propp)
{
    bool found;
    if (!Proxy::has(cx, obj, id, &found))
        return false;

    if (found) {
        propp.setNonNativeProperty();
        objp.set(obj);
    } else {
        propp.setNotFound();
        objp.set(nullptr);
    }
    return true;
}
js::GetOriginalEval(JSContext *cx, HandleObject scope, MutableHandleObject eval)
{
    assertSameCompartment(cx, scope);
    if (!scope->global().getOrCreateObjectPrototype(cx))
        return false;
    eval.set(&scope->global().getOriginalEval().toObject());
    return true;
}
Пример #11
0
JS_NondeterministicGetWeakSetKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
{
    RootedObject obj(cx, UncheckedUnwrap(objArg));
    if (!obj || !obj->is<WeakSetObject>()) {
        ret.set(nullptr);
        return true;
    }
    return WeakCollectionObject::nondeterministicGetKeys(cx, obj.as<WeakCollectionObject>(), ret);
}
Пример #12
0
/* static */ bool
GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
                              MutableHandleObject eval)
{
    if (!global->getOrCreateObjectPrototype(cx))
        return false;
    eval.set(&global->getSlot(EVAL).toObject());
    return true;
}
Пример #13
0
bool
XDRState<mode>::codeFunction(MutableHandleObject objp)
{
    if (mode == XDR_DECODE)
        objp.set(NULL);

    if (!VersionCheck(this))
        return false;

    return XDRInterpretedFunction(this, NullPtr(), NullPtr(), objp);
}
Пример #14
0
static bool
WrapForSameCompartment(JSContext *cx, MutableHandleObject obj, const JSWrapObjectCallbacks *cb)
{
    JS_ASSERT(cx->compartment() == obj->compartment());
    if (!cb->sameCompartmentWrap)
        return true;

    RootedObject wrapped(cx, cb->sameCompartmentWrap(cx, obj));
    if (!wrapped)
        return false;
    obj.set(wrapped);
    return true;
}
Пример #15
0
bool
JSCompartment::getOrCreateWrapper(JSContext* cx, HandleObject existing, MutableHandleObject obj)
{
    // If we already have a wrapper for this value, use it.
    RootedValue key(cx, ObjectValue(*obj));
    if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) {
        obj.set(&p->value().get().toObject());
        MOZ_ASSERT(obj->is<CrossCompartmentWrapperObject>());
        return true;
    }

    // Ensure that the wrappee is exposed in case we are creating a new wrapper
    // for a gray object.
    ExposeObjectToActiveJS(obj);

    // Create a new wrapper for the object.
    auto wrap = cx->runtime()->wrapObjectCallbacks->wrap;
    RootedObject wrapper(cx, wrap(cx, existing, obj));
    if (!wrapper)
        return false;

    // We maintain the invariant that the key in the cross-compartment wrapper
    // map is always directly wrapped by the value.
    MOZ_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject());

    if (!putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*wrapper))) {
        // Enforce the invariant that all cross-compartment wrapper object are
        // in the map by nuking the wrapper if we couldn't add it.
        // Unfortunately it's possible for the wrapper to still be marked if we
        // took this path, for example if the object metadata callback stashes a
        // reference to it.
        if (wrapper->is<CrossCompartmentWrapperObject>())
            NukeCrossCompartmentWrapper(cx, wrapper);
        return false;
    }

    obj.set(wrapper);
    return true;
}
Пример #16
0
static bool
WrapForSameCompartment(JSContext *cx, MutableHandleObject obj)
{
    JS_ASSERT(cx->compartment() == obj->compartment());
    if (!cx->runtime()->sameCompartmentWrapObjectCallback)
        return true;

    RootedObject wrapped(cx);
    wrapped = cx->runtime()->sameCompartmentWrapObjectCallback(cx, obj);
    if (!wrapped)
        return false;
    obj.set(wrapped);
    return true;
}
Пример #17
0
static JSBool
strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                   MutableHandleObject objp)
{
    objp.set(NULL);

    Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());

    unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
    PropertyOp getter = StrictArgGetter;
    StrictPropertyOp setter = StrictArgSetter;

    if (JSID_IS_INT(id)) {
        uint32_t arg = uint32_t(JSID_TO_INT(id));
        if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
            return true;

        attrs |= JSPROP_ENUMERATE;
    } else if (JSID_IS_ATOM(id, cx->names().length)) {
        if (argsobj->hasOverriddenLength())
            return true;
    } else {
        if (!JSID_IS_ATOM(id, cx->names().callee) && !JSID_IS_ATOM(id, cx->names().caller))
            return true;

        attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
        getter = CastAsPropertyOp(argsobj->global().getThrowTypeError());
        setter = CastAsStrictPropertyOp(argsobj->global().getThrowTypeError());
    }

    RootedValue undef(cx, UndefinedValue());
    if (!baseops::DefineGeneric(cx, argsobj, id, undef, getter, setter, attrs))
        return false;

    objp.set(argsobj);
    return true;
}
Пример #18
0
js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScript scriptArg,
                                  MutableHandleObject scopeArg)
{
    CHECK_REQUEST(cx);
    assertSameCompartment(cx, global);
    MOZ_ASSERT(global->is<GlobalObject>());
    MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope());

    RootedScript script(cx, scriptArg);
    Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>());
    if (script->compartment() != cx->compartment()) {
        Rooted<StaticScope*> staticScope(cx, &globalRoot->lexicalScope().staticBlock());
        staticScope = StaticNonSyntacticScope::create(cx, staticScope);
        if (!staticScope)
            return false;
        script = CloneGlobalScript(cx, staticScope, script);
        if (!script)
            return false;

        Debugger::onNewScript(cx, script);
    }

    Rooted<ClonedBlockObject*> globalLexical(cx, &globalRoot->lexicalScope());
    Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalLexical));
    if (!scope)
        return false;

    // Unlike the non-syntactic scope chain API used by the subscript loader,
    // this API creates a fresh block scope each time.
    Rooted<StaticNonSyntacticScope*> enclosingStaticScope(cx,
        &script->enclosingStaticScope()->as<StaticNonSyntacticScope>());
    scope = ClonedBlockObject::createNonSyntactic(cx, enclosingStaticScope, scope);
    if (!scope)
        return false;

    RootedValue rval(cx);
    if (!ExecuteKernel(cx, script, *scope, UndefinedValue(),
                       NullFramePtr() /* evalInFrame */, rval.address()))
    {
        return false;
    }

    scopeArg.set(scope);
    return true;
}
Пример #19
0
static bool
CreateInstance(JSContext* cx, HandleObject exportObj, MutableHandleObject instance)
{
    instance.set(JS_NewPlainObject(cx));
    if (!instance)
        return false;

    JSAtom* atom = Atomize(cx, ExportField, strlen(ExportField));
    if (!atom)
        return false;

    RootedId id(cx, AtomToId(atom));
    RootedValue val(cx, ObjectValue(*exportObj));
    if (!JS_DefinePropertyById(cx, instance, id, val, JSPROP_ENUMERATE))
        return false;

    return true;
}
// ES6 (14 October, 2014) 9.5.11 Proxy.[[Enumerate]]
bool
ScriptedDirectProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
                                      MutableHandleObject objp) const
{
    // step 1
    RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));

    // step 2
    if (!handler) {
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
        return false;
    }

    // step 3: unnecessary assert
    // step 4
    RootedObject target(cx, proxy->as<ProxyObject>().target());

    // step 5-6
    RootedValue trap(cx);
    if (!GetProperty(cx, handler, handler, cx->names().enumerate, &trap))
        return false;

    // step 7
    if (trap.isUndefined())
        return GetIterator(cx, target, 0, objp);

    // step 8-9
    Value argv[] = {
        ObjectOrNullValue(target)
    };
    RootedValue trapResult(cx);
    if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
        return false;

    // step 10
    if (trapResult.isPrimitive()) {
        ReportInvalidTrapResult(cx, proxy, cx->names().enumerate);
        return false;
    }

    // step 11
    objp.set(&trapResult.toObject());
    return true;
}
Пример #21
0
bool
WrapperOwner::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp)
{
    ObjectId objId = idOf(proxy);

    ObjectOrNullVariant val;
    ReturnStatus status;
    if (!SendGetPrototype(objId, &status, &val))
        return ipcfail(cx);

    LOG_STACK();

    if (!ok(cx, status))
        return false;

    objp.set(fromObjectOrNullVariant(cx, val));

    return true;
}
Пример #22
0
bool
CrossCompartmentWrapper::getPrototypeOf(JSContext *cx, HandleObject wrapper,
                                        MutableHandleObject protop)
{
    if (!wrapper->getTaggedProto().isLazy()) {
        protop.set(wrapper->getTaggedProto().toObjectOrNull());
        return true;
    }

    {
        RootedObject wrapped(cx, wrappedObject(wrapper));
        AutoCompartment call(cx, wrapped);
        if (!JSObject::getProto(cx, wrapped, protop))
            return false;
        if (protop)
            protop->setDelegate(cx);
    }

    return cx->compartment->wrap(cx, protop.address());
}
Пример #23
0
static bool
FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result)
{
    // Walk up the prototype chain until we find an error object instance or
    // prototype object. This allows code like:
    //  Object.create(Error.prototype).stack
    // or
    //   function NYI() { }
    //   NYI.prototype = new Error;
    //   (new NYI).stack
    // to continue returning stacks that are useless, but at least don't throw.

    RootedObject target(cx, CheckedUnwrap(obj));
    if (!target) {
        ReportAccessDenied(cx);
        return false;
    }

    RootedObject proto(cx);
    while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) {
        if (!GetPrototype(cx, target, &proto))
            return false;

        if (!proto) {
            // We walked the whole prototype chain and did not find an Error
            // object.
            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                                      js_Error_str, "(get stack)", obj->getClass()->name);
            return false;
        }

        target = CheckedUnwrap(proto);
        if (!target) {
            ReportAccessDenied(cx);
            return false;
        }
    }

    result.set(target);
    return true;
}
Пример #24
0
js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScript scriptArg,
                                  MutableHandleObject scopeArg)
{
    CHECK_REQUEST(cx);
    assertSameCompartment(cx, global);
    MOZ_ASSERT(global->is<GlobalObject>());

    RootedScript script(cx, scriptArg);
    if (script->compartment() != cx->compartment()) {
        script = CloneScript(cx, NullPtr(), NullPtr(), script);
        if (!script)
            return false;

        Debugger::onNewScript(cx, script);
    }

    RootedObject scope(cx, JS_NewPlainObject(cx));
    if (!scope)
        return false;

    if (!scope->setQualifiedVarObj(cx))
        return false;

    if (!scope->setUnqualifiedVarObj(cx))
        return false;

    JSObject* thisobj = GetThisObject(cx, global);
    if (!thisobj)
        return false;

    RootedValue thisv(cx, ObjectValue(*thisobj));
    RootedValue rval(cx);
    if (!ExecuteKernel(cx, script, *scope, thisv, EXECUTE_GLOBAL,
                       NullFramePtr() /* evalInFrame */, rval.address()))
    {
        return false;
    }

    scopeArg.set(scope);
    return true;
}
Пример #25
0
js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScript scriptArg,
                                  MutableHandleObject scopeArg)
{
    CHECK_REQUEST(cx);
    assertSameCompartment(cx, global);
    MOZ_ASSERT(global->is<GlobalObject>());
    MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope());

    RootedScript script(cx, scriptArg);
    if (script->compartment() != cx->compartment()) {
        Rooted<ScopeObject*> staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr));
        if (!staticScope)
            return false;
        script = CloneGlobalScript(cx, staticScope, script);
        if (!script)
            return false;

        Debugger::onNewScript(cx, script);
    }

    Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>());
    Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalRoot));
    if (!scope)
        return false;

    JSObject* thisobj = GetThisObject(cx, global);
    if (!thisobj)
        return false;

    RootedValue thisv(cx, ObjectValue(*thisobj));
    RootedValue rval(cx);
    if (!ExecuteKernel(cx, script, *scope, thisv, UndefinedValue(), EXECUTE_GLOBAL,
                       NullFramePtr() /* evalInFrame */, rval.address()))
    {
        return false;
    }

    scopeArg.set(scope);
    return true;
}
Пример #26
0
bool
WeakCollectionObject::nondeterministicGetKeys(JSContext* cx, Handle<WeakCollectionObject*> obj,
                                              MutableHandleObject ret)
{
    RootedObject arr(cx, NewDenseEmptyArray(cx));
    if (!arr)
        return false;
    if (ObjectValueMap* map = obj->getMap()) {
        // Prevent GC from mutating the weakmap while iterating.
        AutoSuppressGC suppress(cx);
        for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
            JS::ExposeObjectToActiveJS(r.front().key());
            RootedObject key(cx, r.front().key());
            if (!cx->compartment()->wrap(cx, &key))
                return false;
            if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
                return false;
        }
    }
    ret.set(arr);
    return true;
}
Пример #27
0
bool
DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop)
{
    protop.set(NULL);
    return true;
}
Пример #28
0
bool
JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existingArg)
{
    MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(this));
    MOZ_ASSERT(cx->compartment() == this);
    MOZ_ASSERT_IF(existingArg, existingArg->compartment() == cx->compartment());
    MOZ_ASSERT_IF(existingArg, IsDeadProxyObject(existingArg));

    if (!obj)
        return true;
    AutoDisableProxyCheck adpc(cx->runtime());

    // Wrappers should really be parented to the wrapped parent of the wrapped
    // object, but in that case a wrapped global object would have a nullptr
    // 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.
    HandleObject global = cx->global();
    RootedObject objGlobal(cx, &obj->global());
    MOZ_ASSERT(global);
    MOZ_ASSERT(objGlobal);

    const JSWrapObjectCallbacks *cb = cx->runtime()->wrapObjectCallbacks;

    if (obj->compartment() == this) {
        obj.set(GetOuterObject(cx, obj));
        return true;
    }

    // If we have a cross-compartment wrapper, make sure that the cx isn't
    // associated with the self-hosting global. We don't want to create
    // wrappers for objects in other runtimes, which may be the case for the
    // self-hosting global.
    MOZ_ASSERT(!cx->runtime()->isSelfHostingGlobal(global) &&
               !cx->runtime()->isSelfHostingGlobal(objGlobal));

    // Unwrap the object, but don't unwrap outer windows.
    RootedObject objectPassedToWrap(cx, obj);
    obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true));

    if (obj->compartment() == this) {
        MOZ_ASSERT(obj == GetOuterObject(cx, obj));
        return true;
    }

    // Translate StopIteration singleton.
    if (obj->is<StopIterationObject>()) {
        // StopIteration isn't a constructor, but it's stored in GlobalObject
        // as one, out of laziness. Hence the GetBuiltinConstructor call here.
        RootedObject stopIteration(cx);
        if (!GetBuiltinConstructor(cx, JSProto_StopIteration, &stopIteration))
            return false;
        obj.set(stopIteration);
        return true;
    }

    // Invoke the prewrap callback. We're a bit worried about infinite
    // recursion here, so we do a check - see bug 809295.
    JS_CHECK_SYSTEM_RECURSION(cx, return false);
    if (cb->preWrap) {
        obj.set(cb->preWrap(cx, global, obj, objectPassedToWrap));
        if (!obj)
            return false;
    }
    MOZ_ASSERT(obj == GetOuterObject(cx, obj));

    if (obj->compartment() == this)
        return true;


    // If we already have a wrapper for this value, use it.
    RootedValue key(cx, ObjectValue(*obj));
    if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) {
        obj.set(&p->value().get().toObject());
        MOZ_ASSERT(obj->is<CrossCompartmentWrapperObject>());
        MOZ_ASSERT(obj->getParent() == global);
        return true;
    }

    RootedObject existing(cx, existingArg);
    if (existing) {
        // Is it possible to reuse |existing|?
        if (!existing->getTaggedProto().isLazy() ||
            // Note: Class asserted above, so all that's left to check is callability
            existing->isCallable() ||
            existing->getParent() != global ||
            obj->isCallable())
        {
            existing = nullptr;
        }
    }

    obj.set(cb->wrap(cx, existing, obj, global));
    if (!obj)
        return false;

    // We maintain the invariant that the key in the cross-compartment wrapper
    // map is always directly wrapped by the value.
    MOZ_ASSERT(Wrapper::wrappedObject(obj) == &key.get().toObject());

    return putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*obj));
}
Пример #29
0
static JSBool
exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
            MutableHandleObject objp)
{
    JSExnPrivate *priv;
    const char *prop;
    jsval v;
    unsigned attrs;

    objp.set(NULL);
    priv = GetExnPrivate(obj);
    if (priv && JSID_IS_ATOM(id)) {
        RootedString str(cx, JSID_TO_STRING(id));

        RootedAtom atom(cx, cx->names().message);
        if (str == atom) {
            prop = js_message_str;

            /*
             * Per ES5 15.11.1.1, if Error is called with no argument or with
             * undefined as the argument, it returns an Error object with no
             * own message property.
             */
            if (!priv->message)
                return true;

            v = STRING_TO_JSVAL(priv->message);
            attrs = 0;
            goto define;
        }

        atom = cx->names().fileName;
        if (str == atom) {
            prop = js_fileName_str;
            v = STRING_TO_JSVAL(priv->filename);
            attrs = JSPROP_ENUMERATE;
            goto define;
        }

        atom = cx->names().lineNumber;
        if (str == atom) {
            prop = js_lineNumber_str;
            v = UINT_TO_JSVAL(priv->lineno);
            attrs = JSPROP_ENUMERATE;
            goto define;
        }

        atom = cx->names().columnNumber;
        if (str == atom) {
            prop = js_columnNumber_str;
            v = UINT_TO_JSVAL(priv->column);
            attrs = JSPROP_ENUMERATE;
            goto define;
        }

        atom = cx->names().stack;
        if (str == atom) {
            RawString stack = StackTraceToString(cx, priv);
            if (!stack)
                return false;

            prop = js_stack_str;
            v = STRING_TO_JSVAL(stack);
            attrs = JSPROP_ENUMERATE;
            goto define;
        }
    }
    return true;

  define:
    if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, attrs))
        return false;
    objp.set(obj);
    return true;
}
Пример #30
0
static JSBool
global_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
	       MutableHandleObject objp)
{
#ifdef LAZY_STANDARD_CLASSES
    if ((flags & JSRESOLVE_ASSIGNING) == 0) {
        JSBool resolved;

        if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
            return JS_FALSE;
        if (resolved) {
            objp.set(obj);
            return JS_TRUE;
        }
    }
#endif

#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
    if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) {
        /*
         * Do this expensive hack only for unoptimized Unix builds, which are
         * not used for benchmarking.
         */
        char *path, *comp, *full;
        const char *name;
        JSBool ok, found;
        JSFunction *fun;

        if (!JSVAL_IS_STRING(id))
            return JS_TRUE;
        path = getenv("PATH");
        if (!path)
            return JS_TRUE;
        path = JS_strdup(cx, path);
        if (!path)
            return JS_FALSE;
        name = JS_GetStringBytes(JSVAL_TO_STRING(id));
        ok = JS_TRUE;
        for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) {
            if (*comp != '\0') {
                full = JS_smprintf("%s/%s", comp, name);
                if (!full) {
                    JS_ReportOutOfMemory(cx);
                    ok = JS_FALSE;
                    break;
                }
            } else {
                full = (char *)name;
            }
            found = (access(full, X_OK) == 0);
            if (*comp != '\0')
                free(full);
            if (found) {
                fun = JS_DefineFunction(cx, obj, name, Exec, 0, JSPROP_ENUMERATE);
                ok = (fun != NULL);
                if (ok)
                    objp.set(obj);
                break;
            }
        }
        JS_free(cx, path);
        return ok;
    }
#else
    return JS_TRUE;
#endif
}