Bug 1662559 - Part 13: Disallow invocation of private methods inside of evalInFrame r=arai

In order to correctly support this with the optimized storage for methods we
would need new bytecode like GetAliasedVar which is able to traverse
non-EnvironmentObject environments like DebugEnvironmentProxy.

Unfortunately, for safety this means we will ultimately disable this for a number of
different private field and accessor invocations.

Differential Revision: https://phabricator.services.mozilla.com/D109402
This commit is contained in:
Matthew Gaudet 2021-04-19 19:28:08 +00:00
Родитель 0e4955e1f7
Коммит 8f80d4fb4c
5 изменённых файлов: 49 добавлений и 17 удалений

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

@ -560,6 +560,7 @@ MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_RESOLVED, 0, JSEXN_TYPEERR, "Promise hasn't been
MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_FULFILLED, 0, JSEXN_TYPEERR, "Promise hasn't been fulfilled")
MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_REJECTED, 0, JSEXN_TYPEERR, "Promise hasn't been rejected")
MSG_DEF(JSMSG_DEBUG_NO_BINARY_SOURCE, 0, JSEXN_ERR, "WebAssembly binary source is not available")
MSG_DEF(JSMSG_DEBUG_NO_PRIVATE_METHOD, 0, JSEXN_ERR, "private method calls aren't available in this context")
// Testing functions
MSG_DEF(JSMSG_TESTING_SCRIPTS_ONLY, 0, JSEXN_TYPEERR, "only works on scripts")

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

@ -201,9 +201,10 @@ NameLocation BytecodeEmitter::lookupName(TaggedParserAtomIndex name) {
return innermostEmitterScope()->lookup(this, name);
}
NameLocation BytecodeEmitter::lookupPrivate(TaggedParserAtomIndex name,
Maybe<NameLocation>& brandLoc) {
return innermostEmitterScope()->lookupPrivate(this, name, brandLoc);
bool BytecodeEmitter::lookupPrivate(TaggedParserAtomIndex name,
NameLocation& loc,
Maybe<NameLocation>& brandLoc) {
return innermostEmitterScope()->lookupPrivate(this, name, loc, brandLoc);
}
Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScope(

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

@ -226,9 +226,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
NameLocation lookupName(TaggedParserAtomIndex name);
// See EmitterScope::lookupPrivate for details around brandLoc.
NameLocation lookupPrivate(TaggedParserAtomIndex name,
mozilla::Maybe<NameLocation>& brandLoc);
// See EmitterScope::lookupPrivate for details around brandLoc
bool lookupPrivate(TaggedParserAtomIndex name, NameLocation& loc,
mozilla::Maybe<NameLocation>& brandLoc);
// To implement Annex B and the formal parameter defaults scope semantics
// requires accessing names that would otherwise be shadowed. This method

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

@ -990,15 +990,43 @@ NameLocation EmitterScope::lookup(BytecodeEmitter* bce,
return searchAndCache(bce, name);
}
NameLocation EmitterScope::lookupPrivate(
BytecodeEmitter* bce, TaggedParserAtomIndex name,
mozilla::Maybe<NameLocation>& brandLoc) {
NameLocation loc = lookup(bce, name);
bool EmitterScope::lookupPrivate(BytecodeEmitter* bce,
TaggedParserAtomIndex name, NameLocation& loc,
mozilla::Maybe<NameLocation>& brandLoc) {
loc = lookup(bce, name);
// The parser ensures that `name` is the name of a private member in the
// current scope. Since classes are strict mode code, we're certain to find
// that scope statically; there will be no intervening dynamic scope.
MOZ_RELEASE_ASSERT(loc.kind() == NameLocation::Kind::EnvironmentCoordinate);
// Private Brand checking relies on the ability to construct a new
// environment coordinate for a name at a fixed offset, which will
// correspond to the private brand for that class.
//
// Despite easily being able to gather the information required to
// synthesize an environment coordinate (see cachePrivateFieldsForEval, and
// Bug 1638309), we don't have bytecode that is able to bypass the
// DebugEnvironmentProxy on the environment to load the right value. As a
// result, we cannot currently correctly brand check a private method.
//
// See also Bug 793345 which argues that we should remove the
// DebugEnvironmentProxy.
if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) {
MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic ||
loc.kind() == NameLocation::Kind::Global);
// Private fields don't require brand checking and can be correctly
// code-generated with dynamic name lookup bytecode we have today.
//
// In an ideal world, we could check if we have a private field or a private
// method, relying on the private field eval cache; if we have dynamic or
// global name location kind, and we successfully parsed the private
// identifier, then it must be in the eval cache, which tracks binding kind.
// However, we don't initialize the eval cache on delazifications that are
// nested inside an eval execution, so we can't rely on it.
//
// Instead, at this point we throw up our hands and tell the user their
// invocation isn't supported (even if it's actually the invocation of a
// private field, which conceptually -should- work, but we cannot
// disambiguate from a private method invocation without the binding kind.)
bce->reportError(nullptr, JSMSG_DEBUG_NO_PRIVATE_METHOD);
return false;
}
if (loc.bindingKind() == BindingKind::PrivateMethod) {
brandLoc = Some(NameLocation::EnvironmentCoordinate(
@ -1007,7 +1035,7 @@ NameLocation EmitterScope::lookupPrivate(
} else {
brandLoc = Nothing();
}
return loc;
return true;
}
Maybe<NameLocation> EmitterScope::locationBoundInScope(

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

@ -193,8 +193,10 @@ class EmitterScope : public Nestable<EmitterScope> {
// target object (anything other than a non-static private method), then
// `brandLoc` is set to Nothing.
//
NameLocation lookupPrivate(BytecodeEmitter* bce, TaggedParserAtomIndex name,
mozilla::Maybe<NameLocation>& brandLoc);
// To handle cases where it's not possible to find the private brand, this
// method has to be fallible.
bool lookupPrivate(BytecodeEmitter* bce, TaggedParserAtomIndex name,
NameLocation& loc, mozilla::Maybe<NameLocation>& brandLoc);
mozilla::Maybe<NameLocation> locationBoundInScope(TaggedParserAtomIndex name,
EmitterScope* target);