From 6c3e42ac6427fabaf83b5acc7877aa3d15117125 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Thu, 12 Dec 2019 22:41:21 -0500 Subject: Bug 1454285 - Part 2: Disallow using innermostEmitterScope while the value does not match the bytecode environment. Tag #1287 --- js/src/frontend/BytecodeEmitter.cpp | 59 ++++++++++++++++++++----------------- js/src/frontend/BytecodeEmitter.h | 49 ++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index fda01dac2..f4574b248 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -100,7 +100,7 @@ class BytecodeEmitter::NestableControl : public Nestable(&bce->innermostNestableControl), kind_(kind), - emitterScope_(bce->innermostEmitterScope) + emitterScope_(bce->innermostEmitterScopeNoCheck()) { } public: @@ -426,7 +426,7 @@ class BytecodeEmitter::EmitterScope : public Nestableparent) { *bce = (*bce)->parent; - return (*bce)->innermostEmitterScope; + return (*bce)->innermostEmitterScopeNoCheck(); } return nullptr; @@ -460,7 +460,7 @@ class BytecodeEmitter::EmitterScope : public Nestable(&bce->innermostEmitterScope), + : Nestable(&bce->innermostEmitterScope_), nameCache_(bce->cx->frontendCollectionPool()), hasEnvironment_(false), environmentChainLength_(0), @@ -866,7 +866,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind Handle bindings) { MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda); - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); if (!ensureCache(bce)) return false; @@ -935,7 +935,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind bool BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); MOZ_ASSERT(funbox->namedLambdaBindings()); if (!ensureCache(bce)) @@ -1002,7 +1002,7 @@ BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce, bool BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); if (!ensureCache(bce)) return false; @@ -1035,7 +1035,7 @@ BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce) bool BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); // If there are parameter expressions, there is an extra var scope. if (!funbox->hasExtraBodyVarScope()) @@ -1126,7 +1126,7 @@ BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, F MOZ_ASSERT(funbox->hasParameterExprs); MOZ_ASSERT(funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings()); - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); // The extra var scope is never popped once it's entered. It replaces the // function scope as the var emitter scope. @@ -1212,7 +1212,7 @@ class DynamicBindingIter : public BindingIter bool BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); bce->setVarEmitterScope(this); @@ -1272,7 +1272,7 @@ BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedCon bool BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); bce->setVarEmitterScope(this); @@ -1327,7 +1327,7 @@ BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext bool BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); bce->setVarEmitterScope(this); @@ -1384,7 +1384,7 @@ BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedCon bool BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce) { - MOZ_ASSERT(this == bce->innermostEmitterScope); + MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); if (!ensureCache(bce)) return false; @@ -1412,7 +1412,7 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) { // If we aren't leaving the scope due to a non-local jump (e.g., break), // we must be the innermost scope. - MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope); + MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck()); ScopeKind kind = scope(bce)->kind(); switch (kind) { @@ -2123,7 +2123,7 @@ class ForOfLoopControl : public LoopControl bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce, CompletionKind completionKind = CompletionKind::Normal) { - return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope, completionKind); + return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind); } bool emitIteratorCloseInScope(BytecodeEmitter* bce, @@ -2201,8 +2201,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, bodyScopeIndex(UINT32_MAX), varEmitterScope(nullptr), innermostNestableControl(nullptr), - innermostEmitterScope(nullptr), + innermostEmitterScope_(nullptr), innermostTDZCheckCache(nullptr), +#ifdef DEBUG + unstableEmitterScope(false), +#endif constList(cx), scopeList(cx), tryNoteList(cx), @@ -2259,13 +2262,13 @@ BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const NameLocation BytecodeEmitter::lookupName(JSAtom* name) { - return innermostEmitterScope->lookup(this, name); + return innermostEmitterScope()->lookup(this, name); } Maybe BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target) { - return innermostEmitterScope->locationBoundInScope(this, name, target); + return innermostEmitterScope()->locationBoundInScope(this, name, target); } Maybe @@ -2726,7 +2729,7 @@ class NonLocalExitControl : bce_(bce), savedScopeNoteIndex_(bce->scopeNoteList.length()), savedDepth_(bce->stackDepth), - openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()), + openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()), kind_(kind) { } @@ -2772,9 +2775,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta using NestableControl = BytecodeEmitter::NestableControl; using EmitterScope = BytecodeEmitter::EmitterScope; - EmitterScope* es = bce_->innermostEmitterScope; + EmitterScope* es = bce_->innermostEmitterScope(); int npops = 0; + AutoCheckUnstableEmitterScope cues(bce_); + // For 'continue', 'break', and 'return' statements, emit IteratorClose // bytecode inline. 'continue' statements do not call IteratorClose for // the loop they are continuing. @@ -2895,7 +2900,7 @@ BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteTy Scope* BytecodeEmitter::innermostScope() const { - return innermostEmitterScope->scope(this); + return innermostEmitterScope()->scope(this); } bool @@ -3555,7 +3560,7 @@ BytecodeEmitter::needsImplicitThis() return true; // Otherwise see if the current point is under a 'with'. - for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) { + for (EmitterScope* es = innermostEmitterScope(); es; es = es->enclosingInFrame()) { if (es->scope(this)->kind() == ScopeKind::With) return true; } @@ -5206,7 +5211,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri // destructuring declaration needs to initialize the name in // the function scope. The innermost scope is the var scope, // and its enclosing scope is the function scope. - EmitterScope* funScope = innermostEmitterScope->enclosingInFrame(); + EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame(); NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope); if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true)) return false; @@ -7308,7 +7313,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte // bindings inducing an environment, recreate the current environment. DebugOnly forOfTarget = forOfHead->pn_kid1; MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST)); - MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); + MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope()); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); if (headLexicalEmitterScope->hasEnvironment()) { @@ -7490,7 +7495,7 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte // it must be the innermost one. If that scope has closed-over // bindings inducing an environment, recreate the current environment. MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST)); - MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); + MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope()); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); if (headLexicalEmitterScope->hasEnvironment()) { @@ -7619,7 +7624,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc // exists for the head, it must be the innermost one. If that scope // has closed-over bindings inducing an environment, recreate the // current environment. - MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); + MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope()); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); if (headLexicalEmitterScope->hasEnvironment()) { @@ -7667,7 +7672,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc // ES 13.7.4.8 step 3.e. The per-iteration freshening. if (forLoopRequiresFreshening) { - MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); + MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope()); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); if (headLexicalEmitterScope->hasEnvironment()) { @@ -10366,7 +10371,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) { ParseNode* funBody = pn->last(); FunctionBox* funbox = sc->asFunctionBox(); - EmitterScope* funScope = innermostEmitterScope; + EmitterScope* funScope = innermostEmitterScope(); bool hasParameterExprs = funbox->hasParameterExprs; bool hasRest = funbox->hasRest(); diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 36910c3dd..8ad409c11 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -228,9 +228,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter EmitterScope* varEmitterScope; NestableControl* innermostNestableControl; - EmitterScope* innermostEmitterScope; + EmitterScope* innermostEmitterScope_; TDZCheckCache* innermostTDZCheckCache; +#ifdef DEBUG + bool unstableEmitterScope; + + friend class AutoCheckUnstableEmitterScope; +#endif + + EmitterScope* innermostEmitterScope() const { + MOZ_ASSERT(!unstableEmitterScope); + return innermostEmitterScopeNoCheck(); + } + EmitterScope* innermostEmitterScopeNoCheck() const { + return innermostEmitterScope_; + } + CGConstList constList; /* constants to be included with the script */ CGObjectList objectList; /* list of emitted objects */ CGScopeList scopeList; /* list of emitted scopes */ @@ -319,7 +333,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter EmitterScope* source); mozilla::Maybe locationOfNameBoundInFunctionScope(JSAtom* name) { - return locationOfNameBoundInFunctionScope(name, innermostEmitterScope); + return locationOfNameBoundInFunctionScope(name, innermostEmitterScope()); } void setVarEmitterScope(EmitterScope* emitterScope) { @@ -610,7 +624,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitToIteratorResult(bool done); MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() { - return emitGetDotGeneratorInScope(*innermostEmitterScope); + return emitGetDotGeneratorInScope(*innermostEmitterScope()); } MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope); @@ -619,7 +633,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitYieldOp(JSOp op); MOZ_MUST_USE bool emitYieldStar(ParseNode* iter); MOZ_MUST_USE bool emitAwaitInInnermostScope() { - return emitAwaitInScope(*innermostEmitterScope); + return emitAwaitInScope(*innermostEmitterScope()); } MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn); MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope); @@ -729,7 +743,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync, CompletionKind completionKind = CompletionKind::Normal, bool allowSelfHosted = false) { - return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind, + return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind, allowSelfHosted); } @@ -829,6 +843,31 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false); }; +class MOZ_RAII AutoCheckUnstableEmitterScope { +#ifdef DEBUG + bool prev_; + BytecodeEmitter* bce_; +#endif + + public: + AutoCheckUnstableEmitterScope() = delete; + explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce) +#ifdef DEBUG + : bce_(bce) +#endif + { +#ifdef DEBUG + prev_ = bce_->unstableEmitterScope; + bce_->unstableEmitterScope = true; +#endif + } + ~AutoCheckUnstableEmitterScope() { +#ifdef DEBUG + bce_->unstableEmitterScope = prev_; +#endif + } +}; + } /* namespace frontend */ } /* namespace js */ -- cgit v1.2.3