js::NukeCrossCompartmentWrappers(JSContext* cx,
                                 const CompartmentFilter& sourceFilter,
                                 const CompartmentFilter& targetFilter,
                                 js::NukeReferencesToWindow nukeReferencesToWindow,
                                 js::NukeReferencesFromTarget nukeReferencesFromTarget)
{
    CHECK_REQUEST(cx);
    JSRuntime* rt = cx->runtime();

    EvictAllNurseries(rt);

    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
        if (!sourceFilter.match(c))
            continue;

        // If the compartment matches both the source and target filter, we may
        // want to cut both incoming and outgoing wrappers.
        bool nukeAll = (nukeReferencesFromTarget == NukeAllReferences &&
                        targetFilter.match(c));

        // Iterate the wrappers looking for anything interesting.
        for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
            // Some cross-compartment wrappers are for strings.  We're not
            // interested in those.
            const CrossCompartmentKey& k = e.front().key();
            if (!k.is<JSObject*>())
                continue;

            AutoWrapperRooter wobj(cx, WrapperValue(e));
            JSObject* wrapped = UncheckedUnwrap(wobj);

            // We never nuke script source objects, since only ever used internally by the JS
            // engine, and are expected to remain valid throughout a scripts lifetime.
            if (MOZ_UNLIKELY(wrapped->is<ScriptSourceObject>())) {
                continue;
            }

            // We only skip nuking window references that point to a target
            // compartment, not the ones that belong to it.
            if (nukeReferencesToWindow == DontNukeWindowReferences &&
                MOZ_LIKELY(!nukeAll) && IsWindowProxy(wrapped))
            {
                continue;
            }

            if (MOZ_UNLIKELY(nukeAll) || targetFilter.match(wrapped->compartment())) {
                // We found a wrapper to nuke.
                e.removeFront();
                NukeCrossCompartmentWrapper(cx, wobj);
            }
        }
    }

    return true;
}
js::NukeCrossCompartmentWrappers(JSContext* cx,
                                 const CompartmentFilter& sourceFilter,
                                 const CompartmentFilter& targetFilter,
                                 js::NukeReferencesToWindow nukeReferencesToWindow)
{
    CHECK_REQUEST(cx);
    JSRuntime* rt = cx->runtime();

    rt->gc.evictNursery(JS::gcreason::EVICT_NURSERY);

    // Iterate through scopes looking for system cross compartment wrappers
    // that point to an object that shares a global with obj.

    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
        if (!sourceFilter.match(c))
            continue;

        // Iterate the wrappers looking for anything interesting.
        for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
            // Some cross-compartment wrappers are for strings.  We're not
            // interested in those.
            const CrossCompartmentKey& k = e.front().key();
            if (!k.is<JSObject*>())
                continue;

            AutoWrapperRooter wobj(cx, WrapperValue(e));
            JSObject* wrapped = UncheckedUnwrap(wobj);

            if (nukeReferencesToWindow == DontNukeWindowReferences &&
                IsWindowProxy(wrapped))
            {
                continue;
            }

            if (targetFilter.match(wrapped->compartment())) {
                // We found a wrapper to nuke.
                e.removeFront();
                NukeRemovedCrossCompartmentWrapper(cx, wobj);
            }
        }
    }

    return true;
}
js::NukeCrossCompartmentWrappers(JSContext* cx, 
                                 const CompartmentFilter& sourceFilter,
                                 const CompartmentFilter& targetFilter,
                                 js::NukeReferencesToWindow nukeReferencesToWindow)
{
    CHECK_REQUEST(cx);
    JSRuntime *rt = cx->runtime;

    // Iterate through scopes looking for system cross compartment wrappers
    // that point to an object that shares a global with obj.

    for (CompartmentsIter c(rt); !c.done(); c.next()) {
        if (!sourceFilter.match(c))
            continue;

        // Iterate the wrappers looking for anything interesting.
        WrapperMap &pmap = c->crossCompartmentWrappers;
        for (WrapperMap::Enum e(pmap); !e.empty(); e.popFront()) {
            // Some cross-compartment wrappers are for strings.  We're not
            // interested in those.
            const CrossCompartmentKey &k = e.front().key;
            if (k.kind != CrossCompartmentKey::ObjectWrapper)
                continue;

            JSObject *wobj = &e.front().value.get().toObject();
            JSObject *wrapped = UnwrapObject(wobj);

            if (nukeReferencesToWindow == DontNukeWindowReferences &&
                wrapped->getClass()->ext.innerObject)
                continue;

            if (targetFilter.match(wrapped->compartment())) {
                // We found a wrapper to nuke.
                e.removeFront();
                NukeCrossCompartmentWrapper(wobj);
            }
        }
    }

    return JS_TRUE;
}
js::RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
                      const CompartmentFilter &targetFilter)
{
    AutoMaybeTouchDeadCompartments agc(cx);

    AutoWrapperVector toRecompute(cx);

    for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
        // Filter by source compartment.
        if (!sourceFilter.match(c))
            continue;

        // Iterate over the wrappers, filtering appropriately.
        WrapperMap &pmap = c->crossCompartmentWrappers;
        for (WrapperMap::Enum e(pmap); !e.empty(); e.popFront()) {
            // Filter out non-objects.
            const CrossCompartmentKey &k = e.front().key;
            if (k.kind != CrossCompartmentKey::ObjectWrapper)
                continue;

            // Filter by target compartment.
            if (!targetFilter.match(k.wrapped->compartment()))
                continue;

            // Add it to the list.
            if (!toRecompute.append(WrapperValue(e)))
                return false;
        }
    }

    // Recompute all the wrappers in the list.
    for (WrapperValue *begin = toRecompute.begin(), *end = toRecompute.end(); begin != end; ++begin)
    {
        JSObject *wrapper = &begin->toObject();
        JSObject *wrapped = Wrapper::wrappedObject(wrapper);
        if (!RemapWrapper(cx, wrapper, wrapped))
            MOZ_CRASH();
    }

    return true;
}
js::RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
                      const CompartmentFilter& targetFilter)
{
    // Drop any nursery-allocated wrappers.
    EvictAllNurseries(cx->runtime());

    AutoWrapperVector toRecompute(cx);
    for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
        // Filter by source compartment.
        if (!sourceFilter.match(c))
            continue;

        // Iterate over the wrappers, filtering appropriately.
        for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
            // Filter out non-objects.
            CrossCompartmentKey& k = e.front().mutableKey();
            if (!k.is<JSObject*>())
                continue;

            // Filter by target compartment.
            if (!targetFilter.match(k.compartment()))
                continue;

            // Add it to the list.
            if (!toRecompute.append(WrapperValue(e)))
                return false;
        }
    }

    // Recompute all the wrappers in the list.
    for (const WrapperValue& v : toRecompute) {
        JSObject* wrapper = &v.toObject();
        JSObject* wrapped = Wrapper::wrappedObject(wrapper);
        RemapWrapper(cx, wrapper, wrapped);
    }

    return true;
}
js::RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
                      const CompartmentFilter& targetFilter)
{
    AutoWrapperVector toRecompute(cx);

    for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
        // Filter by source compartment.
        if (!sourceFilter.match(c))
            continue;

        // Iterate over the wrappers, filtering appropriately.
        for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
            // Filter out non-objects.
            const CrossCompartmentKey& k = e.front().key();
            if (k.kind != CrossCompartmentKey::ObjectWrapper)
                continue;

            // Filter by target compartment.
            if (!targetFilter.match(static_cast<JSObject*>(k.wrapped)->compartment()))
                continue;

            // Add it to the list.
            if (!toRecompute.append(WrapperValue(e)))
                return false;
        }
    }

    // Recompute all the wrappers in the list.
    for (const WrapperValue& v : toRecompute) {
        JSObject* wrapper = &v.toObject();
        JSObject* wrapped = Wrapper::wrappedObject(wrapper);
        if (!RemapWrapper(cx, wrapper, wrapped))
            MOZ_CRASH();
    }

    return true;
}
示例#7
0
JS_FRIEND_API bool js::RecomputeWrappers(
    JSContext* cx, const CompartmentFilter& sourceFilter,
    const CompartmentFilter& targetFilter) {
  bool evictedNursery = false;

  AutoWrapperVector toRecompute(cx);
  for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
    // Filter by source compartment.
    if (!sourceFilter.match(c)) {
      continue;
    }

    if (!evictedNursery && c->hasNurseryAllocatedWrapperEntries(targetFilter)) {
      cx->runtime()->gc.evictNursery();
      evictedNursery = true;
    }

    // Iterate over the wrappers, filtering appropriately.
    for (Compartment::NonStringWrapperEnum e(c, targetFilter); !e.empty();
         e.popFront()) {
      // Filter out non-objects.
      CrossCompartmentKey& k = e.front().mutableKey();
      if (!k.is<JSObject*>()) {
        continue;
      }

      // Add it to the list.
      if (!toRecompute.append(WrapperValue(e))) {
        return false;
      }
    }
  }

  // Recompute all the wrappers in the list.
  for (const WrapperValue& v : toRecompute) {
    JSObject* wrapper = &v.toObject();
    JSObject* wrapped = Wrapper::wrappedObject(wrapper);
    RemapWrapper(cx, wrapper, wrapped);
  }

  return true;
}
示例#8
0
/*
 * NukeChromeCrossCompartmentWrappersForGlobal reaches into chrome and cuts
 * all of the cross-compartment wrappers that point to an object in the |target|
 * realm. The snag here is that we need to avoid cutting wrappers that point to
 * the window object on page navigation (inner window destruction) and only do
 * that on tab close (outer window destruction).  Thus the option of how to
 * handle the global object.
 */
JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
    JSContext* cx, const CompartmentFilter& sourceFilter, JS::Realm* target,
    js::NukeReferencesToWindow nukeReferencesToWindow,
    js::NukeReferencesFromTarget nukeReferencesFromTarget) {
  CHECK_THREAD(cx);
  JSRuntime* rt = cx->runtime();

  // If we're nuking all wrappers into the target realm, prevent us from
  // creating new wrappers for it in the future.
  if (nukeReferencesFromTarget == NukeAllReferences) {
    target->nukedIncomingWrappers = true;
  }

  for (CompartmentsIter c(rt); !c.done(); c.next()) {
    if (!sourceFilter.match(c)) {
      continue;
    }

    // If the realm matches both the source and target filter, we may want to
    // cut outgoing wrappers too, if we nuked all realms in the compartment.
    bool nukeAll =
        (nukeReferencesFromTarget == NukeAllReferences &&
         target->compartment() == c.get() && NukedAllRealms(c.get()));

    // Iterate only the wrappers that have target compartment matched unless
    // |nukeAll| is true. The string wrappers that we're not interested in
    // won't be iterated, we can exclude them easily because they have
    // compartment nullptr. Use Maybe to avoid copying from conditionally
    // initializing NonStringWrapperEnum.
    mozilla::Maybe<Compartment::NonStringWrapperEnum> e;
    if (MOZ_LIKELY(!nukeAll)) {
      e.emplace(c, target->compartment());
    } else {
      e.emplace(c);
      c.get()->nukedOutgoingWrappers = true;
    }
    for (; !e->empty(); e->popFront()) {
      // Skip debugger references because NukeCrossCompartmentWrapper()
      // doesn't know how to nuke them yet, see bug 1084626 for more
      // information.
      const CrossCompartmentKey& k = e->front().key();
      if (!k.is<JSObject*>()) {
        continue;
      }

      AutoWrapperRooter wobj(cx, WrapperValue(*e));

      // Unwrap from the wrapped object in CrossCompartmentKey instead of
      // the wrapper, this could save us a bit of time.
      JSObject* wrapped = UncheckedUnwrap(k.as<JSObject*>());

      // Don't nuke wrappers for objects in other realms in the target
      // compartment unless nukeAll is set because in that case we want to nuke
      // all outgoing wrappers for the current compartment.
      if (!nukeAll && wrapped->nonCCWRealm() != target) {
        continue;
      }

      // We never nuke ScriptSourceObjects, since they are only ever used
      // internally by the JS engine, and are expected to remain valid
      // throughout a script's lifetime.
      if (MOZ_UNLIKELY(wrapped->is<ScriptSourceObject>())) {
        continue;
      }

      // We only skip nuking window references that point to a target
      // compartment, not the ones that belong to it.
      if (nukeReferencesToWindow == DontNukeWindowReferences &&
          MOZ_LIKELY(!nukeAll) && IsWindowProxy(wrapped)) {
        continue;
      }

      // Now this is the wrapper we want to nuke.
      e->removeFront();
      NukeRemovedCrossCompartmentWrapper(cx, wobj);
    }
  }

  return true;
}
示例#9
0
js::NukeCrossCompartmentWrappers(JSContext* cx,
                                 const CompartmentFilter& sourceFilter,
                                 JSCompartment* target,
                                 js::NukeReferencesToWindow nukeReferencesToWindow,
                                 js::NukeReferencesFromTarget nukeReferencesFromTarget)
{
    CHECK_REQUEST(cx);
    JSRuntime* rt = cx->runtime();

    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
        if (!sourceFilter.match(c))
            continue;

        // If the compartment matches both the source and target filter, we may
        // want to cut both incoming and outgoing wrappers.
        bool nukeAll = (nukeReferencesFromTarget == NukeAllReferences &&
                        target == c.get());

        // Iterate only the wrappers that have target compartment matched unless
        // |nukeAll| is true. The string wrappers that we're not interested in
        // won't be iterated, we can exclude them easily because they have
        // compartment nullptr. Use Maybe to avoid copying from conditionally
        // initializing NonStringWrapperEnum.
        mozilla::Maybe<JSCompartment::NonStringWrapperEnum> e;
        if (MOZ_LIKELY(!nukeAll))
            e.emplace(c, target);
        else
            e.emplace(c);
        for (; !e->empty(); e->popFront()) {
            // Skip debugger references because NukeCrossCompartmentWrapper()
            // doesn't know how to nuke them yet, see bug 1084626 for more
            // information.
            const CrossCompartmentKey& k = e->front().key();
            if (!k.is<JSObject*>())
                continue;

            AutoWrapperRooter wobj(cx, WrapperValue(*e));

            // Unwrap from the wrapped object in CrossCompartmentKey instead of
            // the wrapper, this could save us a bit of time.
            JSObject* wrapped = UncheckedUnwrap(k.as<JSObject*>());

            // We never nuke script source objects, since only ever used internally by the JS
            // engine, and are expected to remain valid throughout a scripts lifetime.
            if (MOZ_UNLIKELY(wrapped->is<ScriptSourceObject>())) {
                continue;
            }

            // We only skip nuking window references that point to a target
            // compartment, not the ones that belong to it.
            if (nukeReferencesToWindow == DontNukeWindowReferences &&
                MOZ_LIKELY(!nukeAll) && IsWindowProxy(wrapped))
            {
                continue;
            }

            // Now this is the wrapper we want to nuke.
            e->removeFront();
            NukeRemovedCrossCompartmentWrapper(cx, wobj);
        }
    }

    return true;
}