Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Wrapper.cpp   Sprache: unbekannt

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "js/Wrapper.h"

#include "jsexn.h"

#include "js/CallAndConstruct.h"      // JS::Construct, JS::IsConstructor
#include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
#include "js/friend/WindowProxy.h"    // js::IsWindowProxy
#include "js/Object.h"                // JS::GetBuiltinClass
#include "js/Proxy.h"
#include "vm/Compartment.h"
#include "vm/ErrorObject.h"
#include "vm/Interpreter.h"
#include "vm/JSContext.h"
#include "vm/ProxyObject.h"
#include "vm/Realm.h"
#include "vm/RegExpObject.h"
#include "vm/WrapperObject.h"

#include "gc/Marking-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"

using namespace js;

bool Wrapper::finalizeInBackground(const Value& priv) const {
  if (!priv.isObject()) {
    return true;
  }

  /*
   * Make the 'background-finalized-ness' of the wrapper the same as the
   * wrapped object, to allow transplanting between them.
   */

  JSObject* wrapped = MaybeForwarded(&priv.toObject());
  gc::AllocKind wrappedKind;
  if (IsInsideNursery(wrapped)) {
    JSRuntime* rt = wrapped->runtimeFromMainThread();
    wrappedKind = wrapped->allocKindForTenure(rt->gc.nursery());
  } else {
    wrappedKind = wrapped->asTenured().getAllocKind();
  }
  return IsBackgroundFinalized(wrappedKind);
}

bool ForwardingProxyHandler::getOwnPropertyDescriptor(
    JSContext* cx, HandleObject proxy, HandleId id,
    MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const {
  assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetOwnPropertyDescriptor(cx, target, id, desc);
}

bool ForwardingProxyHandler::defineProperty(JSContext* cx, HandleObject proxy,
                                            HandleId id,
                                            Handle<PropertyDescriptor> desc,
                                            ObjectOpResult& result) const {
  assertEnteredPolicy(cx, proxy, id, SET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return DefineProperty(cx, target, id, desc, result);
}

bool ForwardingProxyHandler::ownPropertyKeys(
    JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), ENUMERATE);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetPropertyKeys(
      cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
}

bool ForwardingProxyHandler::delete_(JSContext* cx, HandleObject proxy,
                                     HandleId id,
                                     ObjectOpResult& result) const {
  assertEnteredPolicy(cx, proxy, id, SET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return DeleteProperty(cx, target, id, result);
}

bool ForwardingProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
                                       MutableHandleIdVector props) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), ENUMERATE);
  MOZ_ASSERT(
      !hasPrototype());  // Should never be called if there's a prototype.
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return EnumerateProperties(cx, target, props);
}

bool ForwardingProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
                                          MutableHandleObject protop) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetPrototype(cx, target, protop);
}

bool ForwardingProxyHandler::setPrototype(JSContext* cx, HandleObject proxy,
                                          HandleObject proto,
                                          ObjectOpResult& result) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return SetPrototype(cx, target, proto, result);
}

bool ForwardingProxyHandler::getPrototypeIfOrdinary(
    JSContext* cx, HandleObject proxy, bool* isOrdinary,
    MutableHandleObject protop) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetPrototypeIfOrdinary(cx, target, isOrdinary, protop);
}

bool ForwardingProxyHandler::setImmutablePrototype(JSContext* cx,
                                                   HandleObject proxy,
                                                   bool* succeeded) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return SetImmutablePrototype(cx, target, succeeded);
}

bool ForwardingProxyHandler::preventExtensions(JSContext* cx,
                                               HandleObject proxy,
                                               ObjectOpResult& result) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return PreventExtensions(cx, target, result);
}

bool ForwardingProxyHandler::isExtensible(JSContext* cx, HandleObject proxy,
                                          bool* extensible) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return IsExtensible(cx, target, extensible);
}

bool ForwardingProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id,
                                 bool* bp) const {
  assertEnteredPolicy(cx, proxy, id, GET);
  MOZ_ASSERT(
      !hasPrototype());  // Should never be called if there's a prototype.
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return HasProperty(cx, target, id, bp);
}

bool ForwardingProxyHandler::get(JSContext* cx, HandleObject proxy,
                                 HandleValue receiver, HandleId id,
                                 MutableHandleValue vp) const {
  assertEnteredPolicy(cx, proxy, id, GET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetProperty(cx, target, receiver, id, vp);
}

bool ForwardingProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id,
                                 HandleValue v, HandleValue receiver,
                                 ObjectOpResult& result) const {
  assertEnteredPolicy(cx, proxy, id, SET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return SetProperty(cx, target, id, v, receiver, result);
}

bool ForwardingProxyHandler::call(JSContext* cx, HandleObject proxy,
                                  const CallArgs& args) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), CALL);
  RootedValue target(cx, proxy->as<ProxyObject>().private_());

  InvokeArgs iargs(cx);
  if (!FillArgumentsFromArraylike(cx, iargs, args)) {
    return false;
  }

  return js::Call(cx, target, args.thisv(), iargs, args.rval());
}

bool ForwardingProxyHandler::construct(JSContext* cx, HandleObject proxy,
                                       const CallArgs& args) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), CALL);

  RootedValue target(cx, proxy->as<ProxyObject>().private_());
  if (!IsConstructor(target)) {
    ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, target,
                     nullptr);
    return false;
  }

  ConstructArgs cargs(cx);
  if (!FillArgumentsFromArraylike(cx, cargs, args)) {
    return false;
  }

  RootedObject obj(cx);
  if (!Construct(cx, target, cargs, args.newTarget(), &obj)) {
    return false;
  }

  args.rval().setObject(*obj);
  return true;
}

bool ForwardingProxyHandler::hasOwn(JSContext* cx, HandleObject proxy,
                                    HandleId id, bool* bp) const {
  assertEnteredPolicy(cx, proxy, id, GET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return HasOwnProperty(cx, target, id, bp);
}

bool ForwardingProxyHandler::getOwnEnumerablePropertyKeys(
    JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), ENUMERATE);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetPropertyKeys(cx, target, JSITER_OWNONLY, props);
}

bool ForwardingProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test,
                                        NativeImpl impl,
                                        const CallArgs& args) const {
  args.setThis(
      ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
  if (!test(args.thisv())) {
    ReportIncompatible(cx, args);
    return false;
  }

  return CallNativeImpl(cx, impl, args);
}

bool ForwardingProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy,
                                             ESClass* cls) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return JS::GetBuiltinClass(cx, target, cls);
}

bool ForwardingProxyHandler::isArray(JSContext* cx, HandleObject proxy,
                                     JS::IsArrayAnswer* answer) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return IsArray(cx, target, answer);
}

const char* ForwardingProxyHandler::className(JSContext* cx,
                                              HandleObject proxy) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), GET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return GetObjectClassName(cx, target);
}

JSString* ForwardingProxyHandler::fun_toString(JSContext* cx,
                                               HandleObject proxy,
                                               bool isToSource) const {
  assertEnteredPolicy(cx, proxy, JS::PropertyKey::Void(), GET);
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return fun_toStringHelper(cx, target, isToSource);
}

RegExpShared* ForwardingProxyHandler::regexp_toShared(
    JSContext* cx, HandleObject proxy) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return RegExpToShared(cx, target);
}

bool ForwardingProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                              MutableHandleValue vp) const {
  RootedObject target(cx, proxy->as<ProxyObject>().target());
  return Unbox(cx, target, vp);
}

bool ForwardingProxyHandler::isCallable(JSObject* obj) const {
  JSObject* target = obj->as<ProxyObject>().target();
  return target->isCallable();
}

bool ForwardingProxyHandler::isConstructor(JSObject* obj) const {
  JSObject* target = obj->as<ProxyObject>().target();
  return target->isConstructor();
}

JSObject* Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler,
                       const WrapperOptions& options) {
  // If this is a cross-compartment wrapper allocate it in the compartment's
  // first global. See Compartment::globalForNewCCW.
  mozilla::Maybe<AutoRealm> ar;
  if (handler->isCrossCompartmentWrapper()) {
    ar.emplace(cx, &cx->compartment()->globalForNewCCW());
  }
  RootedValue priv(cx, ObjectValue(*obj));
  return NewProxyObject(cx, handler, priv, options.proto(), options);
}

JSObject* Wrapper::Renew(JSObject* existing, JSObject* obj,
                         const Wrapper* handler) {
  existing->as<ProxyObject>().renew(handler, ObjectValue(*obj));
  return existing;
}

JSObject* Wrapper::wrappedObject(JSObject* wrapper) {
  MOZ_ASSERT(wrapper->is<WrapperObject>());
  JSObject* target = wrapper->as<ProxyObject>().target();

  if (target) {
    // A cross-compartment wrapper should never wrap a CCW. We rely on this
    // in the wrapper handlers (we use AutoRealm on our return value, and
    // AutoRealm cannot be used with CCWs).
    MOZ_ASSERT_IF(IsCrossCompartmentWrapper(wrapper),
                  !IsCrossCompartmentWrapper(target));

#ifdef DEBUG
    // An incremental GC will eventually mark the targets of black wrappers
    // black but while it is in progress we can observe gray targets.
    if (!wrapper->runtimeFromMainThread()->gc.isIncrementalGCInProgress() &&
        wrapper->isMarkedBlack()) {
      JS::AssertObjectIsNotGray(target);
    }
#endif

    // Unmark wrapper targets that should be black in case an incremental GC
    // hasn't marked them the correct color yet.
    JS::ExposeObjectToActiveJS(target);
  }

  return target;
}

JS_PUBLIC_API JSObject* js::UncheckedUnwrapWithoutExpose(JSObject* wrapped) {
  while (true) {
    if (!wrapped->is<WrapperObject>() || MOZ_UNLIKELY(IsWindowProxy(wrapped))) {
      break;
    }
    wrapped = wrapped->as<WrapperObject>().target();

    // This can be called from when getting a weakmap key delegate() on a
    // wrapper whose referent has been moved while it is still unmarked.
    if (wrapped) {
      wrapped = MaybeForwarded(wrapped);
    }
  }
  return wrapped;
}

JS_PUBLIC_API JSObject* js::UncheckedUnwrap(JSObject* wrapped,
                                            bool stopAtWindowProxy,
                                            unsigned* flagsp) {
  MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
  MOZ_ASSERT(CurrentThreadCanAccessRuntime(wrapped->runtimeFromAnyThread()));

  unsigned flags = 0;
  while (true) {
    if (!wrapped->is<WrapperObject>() ||
        MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(wrapped))) {
      break;
    }
    flags |= Wrapper::wrapperHandler(wrapped)->flags();
    wrapped = Wrapper::wrappedObject(wrapped);
  }
  if (flagsp) {
    *flagsp = flags;
  }
  return wrapped;
}

JS_PUBLIC_API JSObject* js::CheckedUnwrapStatic(JSObject* obj) {
  while (true) {
    JSObject* wrapper = obj;
    obj = UnwrapOneCheckedStatic(obj);
    if (!obj || obj == wrapper) {
      return obj;
    }
  }
}

JS_PUBLIC_API JSObject* js::UnwrapOneCheckedStatic(JSObject* obj) {
  MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
  MOZ_ASSERT(CurrentThreadCanAccessRuntime(obj->runtimeFromAnyThread()));

  // Note: callers that care about WindowProxy unwrapping should use
  // CheckedUnwrapDynamic or UnwrapOneCheckedDynamic instead of this. We don't
  // unwrap WindowProxy here to preserve legacy behavior and for consistency
  // with CheckedUnwrapDynamic's default stopAtWindowProxy = true.
  if (!obj->is<WrapperObject>() || MOZ_UNLIKELY(IsWindowProxy(obj))) {
    return obj;
  }

  const Wrapper* handler = Wrapper::wrapperHandler(obj);
  return handler->hasSecurityPolicy() ? nullptr : Wrapper::wrappedObject(obj);
}

JS_PUBLIC_API JSObject* js::CheckedUnwrapDynamic(JSObject* obj, JSContext* cx,
                                                 bool stopAtWindowProxy) {
  RootedObject wrapper(cx, obj);
  while (true) {
    JSObject* unwrapped =
        UnwrapOneCheckedDynamic(wrapper, cx, stopAtWindowProxy);
    if (!unwrapped || unwrapped == wrapper) {
      return unwrapped;
    }
    wrapper = unwrapped;
  }
}

JS_PUBLIC_API JSObject* js::UnwrapOneCheckedDynamic(HandleObject obj,
                                                    JSContext* cx,
                                                    bool stopAtWindowProxy) {
  MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
  MOZ_ASSERT(CurrentThreadCanAccessRuntime(obj->runtimeFromAnyThread()));
  // We should know who's asking.
  MOZ_ASSERT(cx);
  MOZ_ASSERT(cx->realm());

  if (!obj->is<WrapperObject>() ||
      MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(obj))) {
    return obj;
  }

  const Wrapper* handler = Wrapper::wrapperHandler(obj);
  if (!handler->hasSecurityPolicy() ||
      handler->dynamicCheckedUnwrapAllowed(obj, cx)) {
    return Wrapper::wrappedObject(obj);
  }

  return nullptr;
}

void js::ReportAccessDenied(JSContext* cx) {
  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                            JSMSG_OBJECT_ACCESS_DENIED);
}

const char Wrapper::family = 0;
const Wrapper Wrapper::singleton((unsigned)0);
const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);

// TODO: this is temporarily annotated as MOZ_GLOBINIT rather than
// MOZ_RUNINIT to avoid clang plugin errors when building with
// explicit resource management enabled (bug 1928633)
MOZ_GLOBINIT JSObject* const Wrapper::defaultProto = TaggedProto::LazyProto;

/* Compartments. */

JSObject* js::TransparentObjectWrapper(JSContext* cx, HandleObject existing,
                                       HandleObject obj) {
  // Allow wrapping outer window proxies.
  MOZ_ASSERT(!obj->is<WrapperObject>() || IsWindowProxy(obj));
  return Wrapper::New(cx, obj, &CrossCompartmentWrapper::singleton);
}

ErrorCopier::~ErrorCopier() {
  JSContext* cx = ar->context();

  // The provenance of Debugger.DebuggeeWouldRun is the topmost locking
  // debugger compartment; it should not be copied around.
  if (ar->origin()->compartment() != cx->compartment() &&
      cx->isExceptionPending() && !cx->isThrowingDebuggeeWouldRun()) {
    RootedValue exc(cx);
    if (cx->getPendingException(&exc) && exc.isObject() &&
        exc.toObject().is<ErrorObject>()) {
      Rooted<SavedFrame*> stack(cx, cx->getPendingExceptionStack());
      cx->clearPendingException();
      ar.reset();
      Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
      if (JSObject* copyobj = CopyErrorObject(cx, errObj)) {
        RootedValue rootedCopy(cx, ObjectValue(*copyobj));
        cx->setPendingException(rootedCopy, stack);
      }
    }
  }
}

96%


[ zur Elbe Produktseite wechseln0.15Quellennavigators  Analyse erneut starten  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge