From 8c6750014cd51b49ed80c2de0c3f2f08772d3966 Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 9 Apr 2023 19:56:58 +0200 Subject: [PATCH] Issue #2142 - Restrict contents of direct eval in fields Based-on: m-c 1542406 --- js/src/frontend/Parser.cpp | 24 ++++++++++++++++++------ js/src/frontend/Parser.h | 5 +++-- js/src/vm/Scope.cpp | 15 +++++++++++---- js/src/vm/Scope.h | 12 ++++++++++-- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index bd7dc40bf7..bc60503b25 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -214,12 +214,18 @@ SharedContext::computeAllowSyntax(Scope* scope) { for (ScopeIter si(scope); si; si++) { if (si.kind() == ScopeKind::Function) { - JSFunction* fun = si.scope()->as().canonicalFunction(); + FunctionScope* funScope = &si.scope()->as(); + JSFunction* fun = funScope->canonicalFunction(); if (fun->isArrow()) continue; allowNewTarget_ = true; allowSuperProperty_ = fun->allowSuperProperty(); allowSuperCall_ = fun->isDerivedClassConstructor(); + if (funScope->isFieldInitializer()) { + allowSuperProperty_ = false; + allowSuperCall_ = false; + allowArguments_ = false; + } return; } } @@ -1881,7 +1887,8 @@ Parser::newEvalScopeData(ParseContext::Scope& scope) template <> Maybe -Parser::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs) +Parser::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs, + bool isFieldInitializer) { Vector positionalFormals(context); Vector formals(context); @@ -1955,6 +1962,8 @@ Parser::newFunctionScopeData(ParseContext::Scope& scope, bool if (!bindings) return Nothing(); + bindings->isFieldInitializer = isFieldInitializer; + // The ordering here is important. See comments in FunctionScope. BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; @@ -2403,7 +2412,8 @@ Parser::finishFunctionScopes(bool isStandaloneFunction) template <> bool -Parser::finishFunction(bool isStandaloneFunction /* = false */) +Parser::finishFunction(bool isStandaloneFunction /* = false */, + bool isFieldInitializer /* = false */) { if (!finishFunctionScopes(isStandaloneFunction)) return false; @@ -2420,7 +2430,8 @@ Parser::finishFunction(bool isStandaloneFunction /* = false */ { Maybe bindings = newFunctionScopeData(pc->functionScope(), - hasParameterExprs); + hasParameterExprs, + isFieldInitializer); if (!bindings) return false; funbox->functionScopeBindings().set(*bindings); @@ -2438,7 +2449,8 @@ Parser::finishFunction(bool isStandaloneFunction /* = false */ template <> bool -Parser::finishFunction(bool isStandaloneFunction /* = false */) +Parser::finishFunction(bool isStandaloneFunction /* = false */, + bool isFieldInitializer /* = false */) { // The LazyScript for a lazily parsed function needs to know its set of // free variables and inner functions so that when it is fully parsed, we @@ -8076,7 +8088,7 @@ Parser::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH handler.setFunctionBody(funNode, initializerBody); - if (!finishFunction()) + if (!finishFunction(false, true)) return null(); if (!leaveInnerFunction(outerpc)) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index f29d5aaeed..5222d6398c 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1572,7 +1572,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); bool finishFunctionScopes(bool isStandaloneFunction); - bool finishFunction(bool isStandaloneFunction = false); + bool finishFunction(bool isStandaloneFunction = false, bool isFieldInitializer = false); bool leaveInnerFunction(ParseContext* outerpc); bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier); @@ -1620,7 +1620,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) mozilla::Maybe newModuleScopeData(ParseContext::Scope& scope); mozilla::Maybe newEvalScopeData(ParseContext::Scope& scope); mozilla::Maybe newFunctionScopeData(ParseContext::Scope& scope, - bool hasParameterExprs); + bool hasParameterExprs, + bool isFieldInitializer); mozilla::Maybe newVarScopeData(ParseContext::Scope& scope); mozilla::Maybe newLexicalScopeData(ParseContext::Scope& scope); LexicalScopeNodeType finishLexicalScope(ParseContext::Scope& scope, Node body); diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 5cb9abaecf..870add219f 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -610,12 +610,14 @@ FunctionScope::create(ExclusiveContext* cx, Handle dataArg, if (!data) return nullptr; - return createWithData(cx, &data, hasParameterExprs, needsEnvironment, fun, enclosing); + return createWithData(cx, &data, hasParameterExprs, dataArg ? dataArg->isFieldInitializer : false, + needsEnvironment, fun, enclosing); } /* static */ FunctionScope* FunctionScope::createWithData(ExclusiveContext* cx, MutableHandle> data, - bool hasParameterExprs, bool needsEnvironment, + bool hasParameterExprs, bool isFieldInitializer, + bool needsEnvironment, HandleFunction fun, HandleScope enclosing) { MOZ_ASSERT(data); @@ -636,6 +638,7 @@ FunctionScope::createWithData(ExclusiveContext* cx, MutableHandleisFieldInitializer = isFieldInitializer; data->hasParameterExprs = hasParameterExprs; data->canonicalFunction.init(fun); @@ -737,16 +740,20 @@ FunctionScope::XDR(XDRState* xdr, HandleFunction fun, HandleScope enclosin uint8_t needsEnvironment; uint8_t hasParameterExprs; + uint8_t isFieldInitializer; uint32_t nextFrameSlot; if (mode == XDR_ENCODE) { needsEnvironment = scope->hasEnvironment(); hasParameterExprs = data->hasParameterExprs; + isFieldInitializer = data->isFieldInitializer; nextFrameSlot = data->nextFrameSlot; } if (!xdr->codeUint8(&needsEnvironment)) return false; if (!xdr->codeUint8(&hasParameterExprs)) return false; + if (!xdr->codeUint8(&isFieldInitializer)) + return false; if (!xdr->codeUint16(&data->nonPositionalFormalStart)) return false; if (!xdr->codeUint16(&data->varStart)) @@ -761,8 +768,8 @@ FunctionScope::XDR(XDRState* xdr, HandleFunction fun, HandleScope enclosin MOZ_ASSERT(!data->nextFrameSlot); } - scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, needsEnvironment, fun, - enclosing)); + scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, !!isFieldInitializer, + needsEnvironment, fun, enclosing)); if (!scope) return false; diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index fc1419bb89..a1e52e3800 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -500,6 +500,9 @@ class FunctionScope : public Scope // bindings. bool hasParameterExprs = false; + // Anonymous functions used in field initializers are limited. + bool isFieldInitializer = false; + // Bindings are sorted by kind in both frames and environments. // // Positional formal parameter names are those that are not @@ -548,8 +551,9 @@ class FunctionScope : public Scope private: static FunctionScope* createWithData(ExclusiveContext* cx, MutableHandle> data, - bool hasParameterExprs, bool needsEnvironment, - HandleFunction fun, HandleScope enclosing); + bool hasParameterExprs, bool isFieldInitializer, + bool needsEnvironment, HandleFunction fun, + HandleScope enclosing); Data& data() { return *reinterpret_cast(data_); @@ -574,6 +578,10 @@ class FunctionScope : public Scope return data().hasParameterExprs; } + bool isFieldInitializer() const { + return data().isFieldInitializer; + } + uint32_t numPositionalFormalParameters() const { return data().nonPositionalFormalStart; }