Ejemplo n.º 1
0
JS_FRIEND_API void js::NukeCrossCompartmentWrapper(JSContext* cx,
                                                   JSObject* wrapper) {
  JS::Compartment* comp = wrapper->compartment();
  auto ptr = comp->lookupWrapper(Wrapper::wrappedObject(wrapper));
  if (ptr) {
    comp->removeWrapper(ptr);
  }
  NukeRemovedCrossCompartmentWrapper(cx, wrapper);
}
Ejemplo n.º 2
0
// Given a cross-compartment wrapper |wobj|, update it to point to
// |newTarget|. This recomputes the wrapper with JS_WrapValue, and thus can be
// useful even if wrapper already points to newTarget.
// This operation crashes on failure rather than leaving the heap in an
// inconsistent state.
void js::RemapWrapper(JSContext* cx, JSObject* wobjArg,
                      JSObject* newTargetArg) {
  MOZ_ASSERT(!IsInsideNursery(wobjArg));
  MOZ_ASSERT(!IsInsideNursery(newTargetArg));

  RootedObject wobj(cx, wobjArg);
  RootedObject newTarget(cx, newTargetArg);
  MOZ_ASSERT(wobj->is<CrossCompartmentWrapperObject>());
  MOZ_ASSERT(!newTarget->is<CrossCompartmentWrapperObject>());
  JSObject* origTarget = Wrapper::wrappedObject(wobj);
  MOZ_ASSERT(origTarget);
  MOZ_ASSERT(!JS_IsDeadWrapper(origTarget),
             "We don't want a dead proxy in the wrapper map");
  Value origv = ObjectValue(*origTarget);
  JS::Compartment* wcompartment = wobj->compartment();
  MOZ_ASSERT(wcompartment != newTarget->compartment());

  AutoDisableProxyCheck adpc;

  // If we're mapping to a different target (as opposed to just recomputing
  // for the same target), we must not have an existing wrapper for the new
  // target, otherwise this will break.
  MOZ_ASSERT_IF(origTarget != newTarget,
                !wcompartment->lookupWrapper(ObjectValue(*newTarget)));

  // The old value should still be in the cross-compartment wrapper map, and
  // the lookup should return wobj.
  WrapperMap::Ptr p = wcompartment->lookupWrapper(origv);
  MOZ_ASSERT(&p->value().unsafeGet()->toObject() == wobj);
  wcompartment->removeWrapper(p);

  // When we remove origv from the wrapper map, its wrapper, wobj, must
  // immediately cease to be a cross-compartment wrapper. Nuke it.
  NukeCrossCompartmentWrapper(cx, wobj);

  // wobj is no longer a cross-compartment wrapper after nuking it, so we can
  // now use nonCCWRealm.
  Realm* wrealm = wobj->nonCCWRealm();

  // First, we wrap it in the new compartment. We try to use the existing
  // wrapper, |wobj|, since it's been nuked anyway. The wrap() function has
  // the choice to reuse |wobj| or not.
  RootedObject tobj(cx, newTarget);
  AutoRealmUnchecked ar(cx, wrealm);
  AutoEnterOOMUnsafeRegion oomUnsafe;
  if (!wcompartment->rewrap(cx, &tobj, wobj)) {
    oomUnsafe.crash("js::RemapWrapper");
  }

  // If wrap() reused |wobj|, it will have overwritten it and returned with
  // |tobj == wobj|. Otherwise, |tobj| will point to a new wrapper and |wobj|
  // will still be nuked. In the latter case, we replace |wobj| with the
  // contents of the new wrapper in |tobj|.
  if (tobj != wobj) {
    // Now, because we need to maintain object identity, we do a brain
    // transplant on the old object so that it contains the contents of the
    // new one.
    JSObject::swap(cx, wobj, tobj);
  }

  // Before swapping, this wrapper came out of wrap(), which enforces the
  // invariant that the wrapper in the map points directly to the key.
  MOZ_ASSERT(Wrapper::wrappedObject(wobj) == newTarget);

  // Update the entry in the compartment's wrapper map to point to the old
  // wrapper, which has now been updated (via reuse or swap).
  MOZ_ASSERT(wobj->is<WrapperObject>());
  if (!wcompartment->putWrapper(cx, CrossCompartmentKey(newTarget),
                                ObjectValue(*wobj))) {
    oomUnsafe.crash("js::RemapWrapper");
  }
}