Bug 1360372 - Avoid rooting hazard when entering atoms compartment (r=sfink)

This patch avoids a rooting hazard involving the atoms compartment. There is
code in jsatom.cpp that enters the atoms compartment while unrooted pointers
are on the stack. Now that enterZoneGroup can potentially yield, this leads to
a rooting hazard. This patch avoids the hazard by using a totally separate path
that avoids enterZoneGroup when entering the atoms compartment.

MozReview-Commit-ID: ExG1ofCbN8C
This commit is contained in:
Bill McCloskey 2017-04-30 20:23:59 -07:00
Родитель a20cb19dce
Коммит bb2fc6efce
4 изменённых файлов: 47 добавлений и 17 удалений

Просмотреть файл

@ -201,10 +201,14 @@ struct JSContext : public JS::RootingContext,
#endif #endif
private: private:
// If |c| or |oldCompartment| is the atoms compartment, the // We distinguish between entering the atoms compartment and all other
// |exclusiveAccessLock| must be held. // compartments. Entering the atoms compartment requires a lock. Also, we
inline void enterCompartment(JSCompartment* c, // don't call enterZoneGroup when entering the atoms compartment since that
const js::AutoLockForExclusiveAccess* maybeLock = nullptr); // can induce GC hazards.
inline void enterNonAtomsCompartment(JSCompartment* c);
inline void enterAtomsCompartment(JSCompartment* c,
const js::AutoLockForExclusiveAccess& lock);
friend class js::AutoCompartment; friend class js::AutoCompartment;
public: public:

Просмотреть файл

@ -451,17 +451,27 @@ JSContext::runningWithTrustedPrincipals()
} }
inline void inline void
JSContext::enterCompartment( JSContext::enterNonAtomsCompartment(JSCompartment* c)
JSCompartment* c,
const js::AutoLockForExclusiveAccess* maybeLock /* = nullptr */)
{ {
enterCompartmentDepth_++; enterCompartmentDepth_++;
if (!c->zone()->isAtomsZone()) MOZ_ASSERT(!c->zone()->isAtomsZone());
enterZoneGroup(c->zone()->group()); enterZoneGroup(c->zone()->group());
c->enter(); c->enter();
setCompartment(c, maybeLock); setCompartment(c, nullptr);
}
inline void
JSContext::enterAtomsCompartment(JSCompartment* c,
const js::AutoLockForExclusiveAccess& lock)
{
enterCompartmentDepth_++;
MOZ_ASSERT(c->zone()->isAtomsZone());
c->enter();
setCompartment(c, &lock);
} }
template <typename T> template <typename T>
@ -469,7 +479,7 @@ inline void
JSContext::enterCompartmentOf(const T& target) JSContext::enterCompartmentOf(const T& target)
{ {
MOZ_ASSERT(JS::CellIsNotGray(target)); MOZ_ASSERT(JS::CellIsNotGray(target));
enterCompartment(target->compartment(), nullptr); enterNonAtomsCompartment(target->compartment());
} }
inline void inline void

Просмотреть файл

@ -1053,8 +1053,11 @@ class AutoCompartment
JSCompartment* origin() const { return origin_; } JSCompartment* origin() const { return origin_; }
protected: protected:
inline AutoCompartment(JSContext* cx, JSCompartment* target);
// Used only for entering the atoms compartment.
inline AutoCompartment(JSContext* cx, JSCompartment* target, inline AutoCompartment(JSContext* cx, JSCompartment* target,
AutoLockForExclusiveAccess* maybeLock = nullptr); AutoLockForExclusiveAccess& lock);
private: private:
AutoCompartment(const AutoCompartment&) = delete; AutoCompartment(const AutoCompartment&) = delete;

Просмотреть файл

@ -44,14 +44,27 @@ js::AutoCompartment::AutoCompartment(JSContext* cx, const T& target)
cx_->enterCompartmentOf(target); cx_->enterCompartmentOf(target);
} }
// Protected constructor that bypasses assertions in enterCompartmentOf. // Protected constructor that bypasses assertions in enterCompartmentOf. Used
// only for entering the atoms compartment.
js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target, js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target,
js::AutoLockForExclusiveAccess* maybeLock /* = nullptr */) js::AutoLockForExclusiveAccess& lock)
: cx_(cx), : cx_(cx),
origin_(cx->compartment()), origin_(cx->compartment()),
maybeLock_(maybeLock) maybeLock_(&lock)
{ {
cx_->enterCompartment(target, maybeLock); MOZ_ASSERT(target->isAtomsCompartment());
cx_->enterAtomsCompartment(target, lock);
}
// Protected constructor that bypasses assertions in enterCompartmentOf. Should
// not be used to enter the atoms compartment.
js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target)
: cx_(cx),
origin_(cx->compartment()),
maybeLock_(nullptr)
{
MOZ_ASSERT(!target->isAtomsCompartment());
cx_->enterNonAtomsCompartment(target);
} }
js::AutoCompartment::~AutoCompartment() js::AutoCompartment::~AutoCompartment()
@ -61,7 +74,7 @@ js::AutoCompartment::~AutoCompartment()
js::AutoAtomsCompartment::AutoAtomsCompartment(JSContext* cx, js::AutoAtomsCompartment::AutoAtomsCompartment(JSContext* cx,
js::AutoLockForExclusiveAccess& lock) js::AutoLockForExclusiveAccess& lock)
: AutoCompartment(cx, cx->atomsCompartment(lock), &lock) : AutoCompartment(cx, cx->atomsCompartment(lock), lock)
{} {}
js::AutoCompartmentUnchecked::AutoCompartmentUnchecked(JSContext* cx, JSCompartment* target) js::AutoCompartmentUnchecked::AutoCompartmentUnchecked(JSContext* cx, JSCompartment* target)