CVE-2018-0979
Description
Chakra scripting engine memory corruption in Microsoft Edge and ChakraCore allows remote code execution via crafted HTML.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Chakra scripting engine memory corruption in Microsoft Edge and ChakraCore allows remote code execution via crafted HTML.
Vulnerability
A remote code execution vulnerability exists in the way that the Chakra scripting engine handles objects in memory in Microsoft Edge, aka "Chakra Scripting Engine Memory Corruption Vulnerability." The bug resides in incorrect byte code generation where ByteCodeGenerator::NeedScopeObjectForArguments and related functions are called statically instead of on the instance, leading to a dereference of uninitialized memory [1][2]. Affected versions include Microsoft Edge on all supported Windows 10 builds and ChakraCore up to version 1.11 [1][3][4].
Exploitation
An attacker can exploit the vulnerability by hosting a specially crafted website that contains malicious JavaScript or by injecting script into a website that processes user-provided content. The user must visit the attacker's page using Microsoft Edge, or an application embedding the vulnerable ChakraCore engine must process the crafted script [1][3]. No authentication or special privileges are required; the attack vector is remote and network-based.
Impact
Successful exploitation allows the attacker to execute arbitrary code in the context of the current user. If the user has administrative rights, the attacker could install programs, view/change/delete data, or create new accounts with full user rights [1]. The vulnerability is a memory corruption that leads to remote code execution, compromising confidentiality, integrity, and availability of the affected system.
Mitigation
Microsoft released security updates on April 10, 2018, as part of the April 2018 Patch Tuesday, which addressed this vulnerability in Microsoft Edge and ChakraCore [1][3]. Users should apply the latest Windows updates. For ChakraCore, Microsoft provided a patch via commit 2637140 [2]. Organizations should prioritize patching given the remote code execution impact and the existence of related CVEs (CVE-2018-0980, CVE-2018-0990, etc.) [1]. No workarounds are documented; updating the affected software is the only mitigation.
- NVD - CVE-2018-0979
- [CVE-2018-0979] Incorrect byte code can cause dereference of uninitia… · chakra-core/ChakraCore@2637140
- Microsoft ChakraCore Scripting Engine CVE-2018-0979 Remote Memory Corruption Vulnerability
- GitHub - chakra-core/ChakraCore: ChakraCore is an open source Javascript engine with a C API.
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
Microsoft.ChakraCoreNuGet | < 1.8.3 | 1.8.3 |
Affected products
3- Range: ChakraCore
Patches
126371402f106[CVE-2018-0979] Incorrect byte code can cause dereference of uninitialized stack location - Internal
9 files changed · +121 −107
lib/Runtime/ByteCode/ByteCodeEmitter.cpp+70 −70 modified@@ -397,7 +397,7 @@ void ByteCodeGenerator::TrackFunctionDeclarationPropertyForDebugger(Symbol *func // Note: we don't have to check symbol->GetIsTrackedForDebugger, as we are not doing actual work here, // which is done in other Track* functions that we call. - if (functionDeclarationSymbol->IsInSlot(funcInfoParent)) + if (functionDeclarationSymbol->IsInSlot(this, funcInfoParent)) { if (functionDeclarationSymbol->GetScope()->GetIsObject()) { @@ -412,7 +412,7 @@ void ByteCodeGenerator::TrackFunctionDeclarationPropertyForDebugger(Symbol *func // Make sure the property has a slot. This will bump up the size of the slot array if necessary. // Note that slot array inner function bindings are tracked even in non-debug mode in order // to keep the lifetime of the closure binding that could escape around for heap enumeration. - functionDeclarationSymbol->EnsureScopeSlot(funcInfoParent); + functionDeclarationSymbol->EnsureScopeSlot(this, funcInfoParent); functionDeclarationSymbol->EnsurePosition(this); this->TrackSlotArrayPropertyForDebugger( this->Writer()->GetCurrentDebuggerScope(), @@ -634,7 +634,7 @@ void ByteCodeGenerator::InitBlockScopedContent(ParseNode *pnodeBlock, Js::Debugg this->m_writer.ElementRootU(op, funcInfo->FindOrAddReferencedPropertyId(propertyId)); } } - else if (sym->IsInSlot(funcInfo) || (scope->GetIsObject() && sym->NeedsSlotAlloc(funcInfo))) + else if (sym->IsInSlot(this, funcInfo) || (scope->GetIsObject() && sym->NeedsSlotAlloc(this, funcInfo))) { if (scope->GetIsObject()) { @@ -684,7 +684,7 @@ void ByteCodeGenerator::InitBlockScopedContent(ParseNode *pnodeBlock, Js::Debugg } // Syms that begin in register may be delay-captured. In debugger mode, such syms // will live only in slots, so tell the debugger to find them there. - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { TrackSlotArrayPropertyForDebugger(debuggerScope, sym, sym->EnsurePosition(this), pnode->nop == knopConstDecl ? Js::DebuggerScopePropertyFlags_Const : Js::DebuggerScopePropertyFlags_None); } @@ -1088,7 +1088,7 @@ void ByteCodeGenerator::DefineCachedFunctions(FuncInfo *funcInfoParent) { this->DefineOneFunction(pnodeFnc, funcInfoParent); } - else if (!sym->IsInSlot(funcInfoParent) && sym->GetLocation() != Js::Constants::NoRegister) + else if (!sym->IsInSlot(this, funcInfoParent) && sym->GetLocation() != Js::Constants::NoRegister) { // If it was defined by InitCachedFuncs, do we need to put it in a register rather than a slot? m_writer.Reg1Unsigned1(Js::OpCode::GetCachedFunc, sym->GetLocation(), slotCount); @@ -1159,7 +1159,7 @@ void EmitAssignmentToFuncName(ParseNode *pnodeFnc, ByteCodeGenerator *byteCodeGe } else { - if (sym->NeedsSlotAlloc(funcInfoParent)) + if (sym->NeedsSlotAlloc(byteCodeGenerator, funcInfoParent)) { if (!sym->GetHasNonCommittedReference() || (funcInfoParent->GetParsedFunctionBody()->DoStackNestedFunc())) @@ -1278,7 +1278,7 @@ Js::RegSlot ByteCodeGenerator::DefineOneFunction(ParseNode *pnodeFnc, FuncInfo * // be sure to track the register location as well. && !(funcInfoParent->IsGlobalFunction() && !isFunctionDeclarationInBlock)) { - if (!funcSymbol->IsInSlot(funcInfoParent)) + if (!funcSymbol->IsInSlot(this, funcInfoParent)) { funcInfoParent->byteCodeFunction->GetFunctionBody()->InsertSymbolToRegSlotList(funcSymbol->GetName(), pnodeFnc->location, funcInfoParent->varRegsCount); } @@ -1337,7 +1337,7 @@ void ByteCodeGenerator::DefineUserVars(FuncInfo *funcInfo) { EmitPropStoreForSpecialSymbol(sym->GetLocation(), sym, sym->GetPid(), funcInfo, true); - if (ShouldTrackDebuggerMetadata() && !sym->IsInSlot(funcInfo)) + if (ShouldTrackDebuggerMetadata() && !sym->IsInSlot(this, funcInfo)) { byteCodeFunction->InsertSymbolToRegSlotList(sym->GetName(), sym->GetLocation(), funcInfo->varRegsCount); } @@ -1401,7 +1401,7 @@ void ByteCodeGenerator::DefineUserVars(FuncInfo *funcInfo) } else if (!sym->IsArguments()) { - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { if (!sym->GetHasNonCommittedReference() || (sym->GetHasFuncAssignment() && funcInfo->GetParsedFunctionBody()->DoStackNestedFunc())) @@ -1414,19 +1414,19 @@ void ByteCodeGenerator::DefineUserVars(FuncInfo *funcInfo) // Undef-initialize the home location if it is a register (not closure-captured, or else capture // is delayed) or a property of an object. - if ((!sym->GetHasInit() && !sym->IsInSlot(funcInfo)) || + if ((!sym->GetHasInit() && !sym->IsInSlot(this, funcInfo)) || (funcInfo->bodyScope->GetIsObject() && !funcInfo->GetHasCachedScope())) { Js::RegSlot reg = sym->GetLocation(); if (reg == Js::Constants::NoRegister) { - Assert(sym->IsInSlot(funcInfo)); + Assert(sym->IsInSlot(this, funcInfo)); reg = funcInfo->AcquireTmpRegister(); } this->m_writer.Reg1(Js::OpCode::LdUndef, reg); this->EmitLocalPropInit(reg, sym, funcInfo); - if (ShouldTrackDebuggerMetadata() && !sym->GetHasInit() && !sym->IsInSlot(funcInfo)) + if (ShouldTrackDebuggerMetadata() && !sym->GetHasInit() && !sym->IsInSlot(this, funcInfo)) { byteCodeFunction->InsertSymbolToRegSlotList(sym->GetName(), reg, funcInfo->varRegsCount); } @@ -1436,7 +1436,7 @@ void ByteCodeGenerator::DefineUserVars(FuncInfo *funcInfo) } else if (ShouldTrackDebuggerMetadata()) { - if (!sym->GetHasInit() && !sym->IsInSlot(funcInfo)) + if (!sym->GetHasInit() && !sym->IsInSlot(this, funcInfo)) { Js::RegSlot reg = sym->GetLocation(); if (reg != Js::Constants::NoRegister) @@ -1509,7 +1509,7 @@ void ByteCodeGenerator::InitBlockScopedNonTemps(ParseNode *pnode, FuncInfo *func auto fnInit = [this, funcInfo](ParseNode *pnode) { Symbol *sym = pnode->sxVar.sym; - if (!sym->IsInSlot(funcInfo) && !sym->GetIsGlobal() && !sym->GetIsModuleImport()) + if (!sym->IsInSlot(this, funcInfo) && !sym->GetIsGlobal() && !sym->GetIsModuleImport()) { this->m_writer.Reg1(Js::OpCode::InitUndecl, pnode->sxVar.sym->GetLocation()); } @@ -1609,7 +1609,7 @@ void ByteCodeGenerator::EmitScopeObjectInit(FuncInfo *funcInfo) MapFormalsWithoutRest(pnodeFnc, initArg); // If the rest is in the slot - we need to keep that slot. - if (pnodeFnc->sxFnc.pnodeRest != nullptr && pnodeFnc->sxFnc.pnodeRest->sxVar.sym->IsInSlot(funcInfo)) + if (pnodeFnc->sxFnc.pnodeRest != nullptr && pnodeFnc->sxFnc.pnodeRest->sxVar.sym->IsInSlot(this, funcInfo)) { Symbol::SaveToPropIdArray(pnodeFnc->sxFnc.pnodeRest->sxVar.sym, propIds, this); } @@ -1820,9 +1820,9 @@ void ByteCodeGenerator::InitScopeSlotArray(FuncInfo * funcInfo) propertyIdsForScopeSlotArray[slot] = propId; }; - auto setPropIdsForScopeSlotArray = [funcInfo, setPropertyIdForScopeSlotArray](Symbol *const sym) + auto setPropIdsForScopeSlotArray = [this, funcInfo, setPropertyIdForScopeSlotArray](Symbol *const sym) { - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { // All properties should get correct propertyId here. Assert(sym->HasScopeSlot()); // We can't allocate scope slot now. Any symbol needing scope slot must have allocated it before this point. @@ -1882,7 +1882,7 @@ void ByteCodeGenerator::LoadAllConstants(FuncInfo *funcInfo) uint count = 0; funcInfo->GetBodyScope()->ForEachSymbol([&](Symbol *const sym) { - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { // All properties should get correct propertyId here. count++; @@ -1893,7 +1893,7 @@ void ByteCodeGenerator::LoadAllConstants(FuncInfo *funcInfo) { funcInfo->GetParamScope()->ForEachSymbol([&](Symbol *const sym) { - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { // All properties should get correct propertyId here. count++; @@ -2063,7 +2063,7 @@ void ByteCodeGenerator::LoadAllConstants(FuncInfo *funcInfo) Js::RegSlot ldFuncExprDst = sym->GetLocation(); this->m_writer.Reg1(Js::OpCode::LdFuncExpr, ldFuncExprDst); - if (sym->IsInSlot(funcInfo)) + if (sym->IsInSlot(this, funcInfo)) { Js::RegSlot scopeLocation; AnalysisAssert(funcInfo->funcExprScope); @@ -2360,12 +2360,12 @@ void ByteCodeGenerator::HomeArguments(FuncInfo *funcInfo) if (ShouldTrackDebuggerMetadata()) { // Add formals to the debugger propertyidcontainer for reg slots - auto addFormalsToPropertyIdContainer = [funcInfo](ParseNode *pnodeFormal) + auto addFormalsToPropertyIdContainer = [this, funcInfo](ParseNode *pnodeFormal) { if (pnodeFormal->IsVarLetOrConst()) { Symbol* formal = pnodeFormal->sxVar.sym; - if (!formal->IsInSlot(funcInfo)) + if (!formal->IsInSlot(this, funcInfo)) { Assert(!formal->GetHasInit()); funcInfo->GetParsedFunctionBody()->InsertSymbolToRegSlotList(formal->GetName(), formal->GetLocation(), funcInfo->varRegsCount); @@ -2625,7 +2625,7 @@ void ByteCodeGenerator::EmitDefaultArgs(FuncInfo *funcInfo, ParseNode *pnode) Emit(pnodeArg->sxVar.pnodeInit, this, funcInfo, false); pnodeArg->sxVar.sym->SetNeedDeclaration(false); // After emit to prevent foo(a = a) - if (funcInfo->GetHasArguments() && pnodeArg->sxVar.sym->IsInSlot(funcInfo)) + if (funcInfo->GetHasArguments() && pnodeArg->sxVar.sym->IsInSlot(this, funcInfo)) { EmitPropStore(pnodeArg->sxVar.pnodeInit->location, pnodeArg->sxVar.sym, pnodeArg->sxVar.pid, funcInfo, true); @@ -2640,7 +2640,7 @@ void ByteCodeGenerator::EmitDefaultArgs(FuncInfo *funcInfo, ParseNode *pnode) m_writer.MarkLabel(noDefaultLabel); - if (funcInfo->GetHasArguments() && pnodeArg->sxVar.sym->IsInSlot(funcInfo)) + if (funcInfo->GetHasArguments() && pnodeArg->sxVar.sym->IsInSlot(this, funcInfo)) { EmitPropStore(location, pnodeArg->sxVar.sym, pnodeArg->sxVar.pid, funcInfo, true); @@ -2936,7 +2936,7 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode) if (sym != nullptr && sym->IsSpecialSymbol()) { EmitPropStoreForSpecialSymbol(sym->GetLocation(), sym, sym->GetPid(), funcInfo, true); - if (ShouldTrackDebuggerMetadata() && !sym->IsInSlot(funcInfo)) + if (ShouldTrackDebuggerMetadata() && !sym->IsInSlot(this, funcInfo)) { byteCodeFunction->InsertSymbolToRegSlotList(sym->GetName(), sym->GetLocation(), funcInfo->varRegsCount); } @@ -3049,16 +3049,16 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode) Symbol* varSym = funcInfo->GetBodyScope()->FindLocalSymbol(param->GetName()); if ((funcSym == nullptr || funcSym != param) // Do not copy the symbol over to body as the function expression symbol // is expected to stay inside the function expression scope - && (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister))) + && (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(this, funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister))) { if (!varSym->GetNeedDeclaration()) { - if (param->IsInSlot(funcInfo)) + if (param->IsInSlot(this, funcInfo)) { // Simulating EmitPropLoad here. We can't directly call the method as we have to use the param scope specifically. // Walking the scope chain is not possible at this time. Js::RegSlot tempReg = funcInfo->AcquireTmpRegister(); - Js::PropertyId slot = param->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = param->EnsureScopeSlot(this, funcInfo); Js::ProfileId profileId = funcInfo->FindOrAddSlotProfileId(paramScope, slot); Js::OpCode op = paramScope->GetIsObject() ? Js::OpCode::LdParamObjSlot : Js::OpCode::LdParamSlot; slot = slot + (paramScope->GetIsObject() ? 0 : Js::ScopeSlots::FirstSlotIndex); @@ -3442,7 +3442,7 @@ void ByteCodeGenerator::EmitScopeList(ParseNode *pnode, ParseNode *breakOnBodySc } } -void EnsureFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo) +void ByteCodeGenerator::EnsureFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo) { if (pnodeFnc->sxFnc.pnodeName) { @@ -3452,21 +3452,21 @@ void EnsureFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo) // We will allocate scope slot for the arguments symbol during EmitLocalPropInit. if (sym && !sym->IsArguments()) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } } // Similar to EnsureFncScopeSlot visitor function, but verifies that a slot is needed before assigning it. -void CheckFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo) +void ByteCodeGenerator::CheckFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo) { if (pnodeFnc->sxFnc.pnodeName && pnodeFnc->sxFnc.pnodeName->nop == knopVarDecl) { Assert(pnodeFnc->sxFnc.pnodeName->nop == knopVarDecl); Symbol *sym = pnodeFnc->sxFnc.pnodeName->sxVar.sym; - if (sym && sym->NeedsSlotAlloc(funcInfo)) + if (sym && sym->NeedsSlotAlloc(this, funcInfo)) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } } @@ -3517,7 +3517,7 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) { funcInfo->paramScope->AddSymbol(sym); } - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); if (sym->GetHasNonLocalReference()) { sym->GetScope()->SetHasOwnLocalInClosure(true); @@ -3602,34 +3602,34 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) { if (pnode->IsVarLetOrConst()) { - pnode->sxVar.sym->EnsureScopeSlot(funcInfo); + pnode->sxVar.sym->EnsureScopeSlot(this, funcInfo); } }); - MapFormalsFromPattern(pnodeFnc, [&](ParseNode *pnode) { pnode->sxVar.sym->EnsureScopeSlot(funcInfo); }); + MapFormalsFromPattern(pnodeFnc, [&](ParseNode *pnode) { pnode->sxVar.sym->EnsureScopeSlot(this, funcInfo); }); // Only allocate scope slot for "arguments" when really necessary. "hasDeferredChild" // doesn't require scope slot for "arguments" because inner functions can't access // outer function's arguments directly. sym = funcInfo->GetArgumentsSymbol(); Assert(sym); - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } sym = funcInfo->root->sxFnc.GetFuncSymbol(); - if (sym && sym->NeedsSlotAlloc(funcInfo)) + if (sym && sym->NeedsSlotAlloc(this, funcInfo)) { if (funcInfo->funcExprScope && funcInfo->funcExprScope->GetIsObject()) { sym->SetScopeSlot(0); } else if (funcInfo->GetFuncExprNameReference()) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } @@ -3646,13 +3646,13 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) // The position should match the location; otherwise, it has been shadowed by parameter with the same name. if (formal->GetLocation() + 1 == pos) { - pnode->sxVar.sym->EnsureScopeSlot(funcInfo); + pnode->sxVar.sym->EnsureScopeSlot(this, funcInfo); } } pos++; }; MapFormals(pnodeFnc, moveArgToReg); - MapFormalsFromPattern(pnodeFnc, [&](ParseNode *pnode) { pnode->sxVar.sym->EnsureScopeSlot(funcInfo); }); + MapFormalsFromPattern(pnodeFnc, [&](ParseNode *pnode) { pnode->sxVar.sym->EnsureScopeSlot(this, funcInfo); }); } for (pnode = pnodeFnc->sxFnc.pnodeVars; pnode; pnode = pnode->sxVar.pnodeNext) @@ -3666,7 +3666,7 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) } if (sym->GetSymbolType() == STVariable && !sym->IsArguments()) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } } @@ -3719,9 +3719,9 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) { sym = funcInfo->bodyScope->FindLocalSymbol(sym->GetName()); } - if (sym->GetSymbolType() == STVariable && sym->NeedsSlotAlloc(funcInfo) && !sym->IsArguments()) + if (sym->GetSymbolType() == STVariable && sym->NeedsSlotAlloc(this, funcInfo) && !sym->IsArguments()) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } } @@ -3731,9 +3731,9 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) if (pnode->IsVarLetOrConst()) { sym = pnode->sxVar.sym; - if (sym->GetSymbolType() == STFormal && sym->NeedsSlotAlloc(funcInfo)) + if (sym->GetSymbolType() == STFormal && sym->NeedsSlotAlloc(this, funcInfo)) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } }; @@ -3748,7 +3748,7 @@ void ByteCodeGenerator::StartEmitFunction(ParseNode *pnodeFnc) // There is no eval so the arguments may be captured in a lambda. // But we cannot relay on slots getting allocated while the lambda is emitted as the function body may be reparsed. - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } if (pnodeFnc->sxFnc.pnodeBody) @@ -3889,9 +3889,9 @@ void ByteCodeGenerator::EnsureLetConstScopeSlots(ParseNode *pnodeBlock, FuncInfo auto ensureLetConstSlots = ([this, funcInfo, callsEval](ParseNode *pnode) { Symbol *sym = pnode->sxVar.sym; - if (callsEval || sym->NeedsSlotAlloc(funcInfo)) + if (callsEval || sym->NeedsSlotAlloc(this, funcInfo)) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); this->ProcessCapturedSym(sym); } }); @@ -3986,9 +3986,9 @@ void ByteCodeGenerator::StartEmitCatch(ParseNode *pnodeCatch) } Assert(sym->GetScopeSlot() == Js::Constants::NoProperty); - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } }); @@ -4010,12 +4010,12 @@ void ByteCodeGenerator::StartEmitCatch(ParseNode *pnodeCatch) if (scope->GetMustInstantiate()) { - if (sym->IsInSlot(funcInfo)) + if (sym->IsInSlot(this, funcInfo)) { // Since there is only one symbol we are pushing to slot. // Also in order to make IsInSlot to return true - forcing the sym-has-non-local-reference. this->ProcessCapturedSym(sym); - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); } } @@ -4394,10 +4394,10 @@ void ByteCodeGenerator::EmitLocalPropInit(Js::RegSlot rhsLocation, Symbol *sym, Scope *scope = sym->GetScope(); // Check consistency of sym->IsInSlot. - Assert(sym->NeedsSlotAlloc(funcInfo) || sym->GetScopeSlot() == Js::Constants::NoProperty); + Assert(sym->NeedsSlotAlloc(this, funcInfo) || sym->GetScopeSlot() == Js::Constants::NoProperty); // Arrived at the scope in which the property was defined. - if (sym->NeedsSlotAlloc(funcInfo)) + if (sym->NeedsSlotAlloc(this, funcInfo)) { // The property is in memory rather than register. We'll have to load it from the slots. if (scope->GetIsObject()) @@ -4431,7 +4431,7 @@ void ByteCodeGenerator::EmitLocalPropInit(Js::RegSlot rhsLocation, Symbol *sym, else { // Make sure the property has a slot. This will bump up the size of the slot array if necessary. - Js::PropertyId slot = sym->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = sym->EnsureScopeSlot(this, funcInfo); Js::RegSlot slotReg = scope->GetCanMerge() ? funcInfo->frameSlotsRegister : scope->GetLocation(); // Now store the property to its slot. Js::OpCode op = this->GetStSlotOp(scope, -1, slotReg, false, funcInfo); @@ -4728,7 +4728,7 @@ void ByteCodeGenerator::EmitPropStore(Js::RegSlot rhsLocation, Symbol *sym, Iden this->m_writer.W1(Js::OpCode::RuntimeTypeError, SCODE_CODE(JSERR_CantAssignToReadOnly)); } } - else if (sym->IsInSlot(funcInfo) || envIndex != -1) + else if (sym->IsInSlot(this, funcInfo) || envIndex != -1) { if (!isConstDecl && sym->GetIsConst()) { @@ -4738,7 +4738,7 @@ void ByteCodeGenerator::EmitPropStore(Js::RegSlot rhsLocation, Symbol *sym, Iden Js::OpCode::RuntimeTypeError, SCODE_CODE(ERRAssignmentToConst)); } // Make sure the property has a slot. This will bump up the size of the slot array if necessary. - Js::PropertyId slot = sym->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = sym->EnsureScopeSlot(this, funcInfo); bool chkBlockVar = !isLetDecl && !isConstDecl && NeedCheckBlockVar(sym, scope, funcInfo); // The property is in memory rather than register. We'll have to load it from the slots. @@ -5042,9 +5042,9 @@ void ByteCodeGenerator::EmitPropLoad(Js::RegSlot lhsLocation, Symbol *sym, Ident if (sym && sym->GetNeedDeclaration() && scope->GetFunc() == funcInfo && !skipUseBeforeDeclarationCheck) { // Ensure this symbol has a slot if it needs one. - if (sym->IsInSlot(funcInfo)) + if (sym->IsInSlot(this, funcInfo)) { - Js::PropertyId slot = sym->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = sym->EnsureScopeSlot(this, funcInfo); funcInfo->FindOrAddSlotProfileId(scope, slot); } @@ -5124,10 +5124,10 @@ void ByteCodeGenerator::EmitPropLoad(Js::RegSlot lhsLocation, Symbol *sym, Ident } } } - else if (sym->IsInSlot(funcInfo) || envIndex != -1) + else if (sym->IsInSlot(this, funcInfo) || envIndex != -1) { // Make sure the property has a slot. This will bump up the size of the slot array if necessary. - Js::PropertyId slot = sym->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = sym->EnsureScopeSlot(this, funcInfo); Js::ProfileId profileId = funcInfo->FindOrAddSlotProfileId(scope, slot); bool chkBlockVar = NeedCheckBlockVar(sym, scope, funcInfo); Js::OpCode op; @@ -5310,7 +5310,7 @@ void ByteCodeGenerator::EmitPropDelete(Js::RegSlot lhsLocation, Symbol *sym, Ide else { // The delete will look like a non-local reference, so make sure a slot is reserved. - sym->EnsureScopeSlot(funcInfo); + sym->EnsureScopeSlot(this, funcInfo); this->m_writer.Reg1(Js::OpCode::LdFalse, lhsLocation); } @@ -5462,9 +5462,9 @@ void ByteCodeGenerator::EmitPropTypeof(Js::RegSlot lhsLocation, Symbol *sym, Ide if (sym && sym->GetNeedDeclaration() && scope->GetFunc() == funcInfo) { // Ensure this symbol has a slot if it needs one. - if (sym->IsInSlot(funcInfo)) + if (sym->IsInSlot(this, funcInfo)) { - Js::PropertyId slot = sym->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = sym->EnsureScopeSlot(this, funcInfo); funcInfo->FindOrAddSlotProfileId(scope, slot); } @@ -5493,10 +5493,10 @@ void ByteCodeGenerator::EmitPropTypeof(Js::RegSlot lhsLocation, Symbol *sym, Ide this->EmitTypeOfFld(funcInfo, propertyId, lhsLocation, ByteCodeGenerator::RootObjectRegister, Js::OpCode::LdRootFldForTypeOf); } } - else if (sym->IsInSlot(funcInfo) || envIndex != -1) + else if (sym->IsInSlot(this, funcInfo) || envIndex != -1) { // Make sure the property has a slot. This will bump up the size of the slot array if necessary. - Js::PropertyId slot = sym->EnsureScopeSlot(funcInfo); + Js::PropertyId slot = sym->EnsureScopeSlot(this, funcInfo); Js::ProfileId profileId = funcInfo->FindOrAddSlotProfileId(scope, slot); Js::RegSlot tmpLocation = funcInfo->AcquireTmpRegister(); bool chkBlockVar = NeedCheckBlockVar(sym, scope, funcInfo); @@ -5877,7 +5877,7 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI { funcInfo->AcquireLoc(pnode->sxCall.pnodeTarget); } - if (sym && (sym->IsInSlot(funcInfo) || sym->GetScope()->GetFunc() != funcInfo)) + if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo)) { // Can't get the value from the assigned register, so load it here. EmitLoad(pnode->sxCall.pnodeTarget, byteCodeGenerator, funcInfo); @@ -11368,7 +11368,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func auto ParamTrackAndInitialization = [&](Symbol *sym, bool initializeParam, Js::RegSlot location) { - if (sym->IsInSlot(funcInfo)) + if (sym->IsInSlot(byteCodeGenerator, funcInfo)) { Assert(scope->GetMustInstantiate()); if (scope->GetIsObject())
lib/Runtime/ByteCode/ByteCodeGenerator.cpp+14 −13 modified@@ -2545,7 +2545,7 @@ FuncInfo* PreVisitFunction(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerato } PreVisitBlock(pnode->sxFnc.pnodeScopes, byteCodeGenerator); // If we have arguments, we are going to need locations if the function is in strict mode or we have a non-simple parameter list. This is because we will not create a scope object. - bool assignLocationForFormals = !ByteCodeGenerator::NeedScopeObjectForArguments(funcInfo, funcInfo->root); + bool assignLocationForFormals = !byteCodeGenerator->NeedScopeObjectForArguments(funcInfo, funcInfo->root); AddArgsToScope(pnode, byteCodeGenerator, assignLocationForFormals); return funcInfo; @@ -2605,7 +2605,7 @@ void AssignFuncSymRegister(ParseNode * pnode, ByteCodeGenerator * byteCodeGenera Symbol * functionScopeVarSym = sym->GetFuncScopeVarSym(); if (functionScopeVarSym && !functionScopeVarSym->GetIsGlobal() && - !functionScopeVarSym->IsInSlot(sym->GetScope()->GetFunc())) + !functionScopeVarSym->IsInSlot(byteCodeGenerator, sym->GetScope()->GetFunc())) { byteCodeGenerator->AssignRegister(functionScopeVarSym); } @@ -2780,7 +2780,7 @@ FuncInfo* PostVisitFunction(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerat { if (top->GetCallsEval() || top->GetChildCallsEval() || - (top->GetHasArguments() && ByteCodeGenerator::NeedScopeObjectForArguments(top, pnode)) || + (top->GetHasArguments() && byteCodeGenerator->NeedScopeObjectForArguments(top, pnode)) || top->GetHasLocalInClosure() || (top->funcExprScope && top->funcExprScope->GetMustInstantiate()) || // When we have split scope normally either eval will be present or the GetHasLocalInClosure will be true as one of the formal is @@ -2849,10 +2849,10 @@ FuncInfo* PostVisitFunction(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerat }; // We need to include the rest as well -as it will get slot assigned. - if (ByteCodeGenerator::NeedScopeObjectForArguments(top, pnode)) + if (byteCodeGenerator->NeedScopeObjectForArguments(top, pnode)) { MapFormals(pnode, setArgScopeSlot); - if (argSym->NeedsSlotAlloc(top)) + if (argSym->NeedsSlotAlloc(byteCodeGenerator, top)) { Assert(argSym->GetScopeSlot() == Js::Constants::NoProperty); argSym->SetScopeSlot(i++); @@ -2863,7 +2863,7 @@ FuncInfo* PostVisitFunction(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerat top->paramScope->SetScopeSlotCount(i); Assert(top->GetHasHeapArguments()); - if (ByteCodeGenerator::NeedScopeObjectForArguments(top, pnode) + if (byteCodeGenerator->NeedScopeObjectForArguments(top, pnode) && !pnode->sxFnc.HasNonSimpleParameterList()) { top->byteCodeFunction->SetHasImplicitArgIns(false); @@ -3068,7 +3068,7 @@ void ByteCodeGenerator::ProcessCapturedSym(Symbol *sym) FuncInfo *funcHome = sym->GetScope()->GetFunc(); FuncInfo *funcChild = funcHome->GetCurrentChildFunction(); - Assert(sym->NeedsSlotAlloc(funcHome) || sym->GetIsGlobal() || sym->GetIsModuleImport() || sym->GetIsModuleExportStorage()); + Assert(sym->NeedsSlotAlloc(this, funcHome) || sym->GetIsGlobal() || sym->GetIsModuleImport() || sym->GetIsModuleExportStorage()); // If this is not a local property, or not all its references can be tracked, or // it's not scoped to the function, or we're in debug mode, disable the delayed capture optimization. @@ -4953,11 +4953,11 @@ void AssignRegisters(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator) } // Don't give the declared var a register if it's in a closure, because the closure slot // is its true "home". (Need to check IsGlobal again as the sym may have changed above.) - if (!sym->GetIsGlobal() && !sym->IsInSlot(funcInfo)) + if (!sym->GetIsGlobal() && !sym->IsInSlot(byteCodeGenerator, funcInfo)) { if (PHASE_TRACE(Js::DelayCapturePhase, funcInfo->byteCodeFunction)) { - if (sym->NeedsSlotAlloc(byteCodeGenerator->TopFuncInfo())) + if (sym->NeedsSlotAlloc(byteCodeGenerator, byteCodeGenerator->TopFuncInfo())) { Output::Print(_u("--- DelayCapture: Delayed capturing symbol '%s' during initialization.\n"), sym->GetName().GetBuffer()); @@ -5011,12 +5011,12 @@ void AssignRegisters(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator) if (!sym->GetIsGlobal() && !sym->GetIsMember() && byteCodeGenerator->TopFuncInfo() == sym->GetScope()->GetEnclosingFunc() && - !sym->IsInSlot(byteCodeGenerator->TopFuncInfo()) && + !sym->IsInSlot(byteCodeGenerator, byteCodeGenerator->TopFuncInfo()) && !sym->HasVisitedCapturingFunc()) { if (PHASE_TRACE(Js::DelayCapturePhase, byteCodeGenerator->TopFuncInfo()->byteCodeFunction)) { - if (sym->NeedsSlotAlloc(byteCodeGenerator->TopFuncInfo())) + if (sym->NeedsSlotAlloc(byteCodeGenerator, byteCodeGenerator->TopFuncInfo())) { Output::Print(_u("--- DelayCapture: Delayed capturing symbol '%s'.\n"), sym->GetName().GetBuffer()); @@ -5177,8 +5177,7 @@ Js::FunctionBody * ByteCodeGenerator::MakeGlobalFunctionBody(ParseNode *pnode) return func; } -/* static */ -bool ByteCodeGenerator::NeedScopeObjectForArguments(FuncInfo *funcInfo, ParseNode *pnodeFnc) +bool ByteCodeGenerator::NeedScopeObjectForArguments(FuncInfo *funcInfo, ParseNode *pnodeFnc) const { // We can avoid creating a scope object with arguments present if: bool dontNeedScopeObject = @@ -5187,6 +5186,8 @@ bool ByteCodeGenerator::NeedScopeObjectForArguments(FuncInfo *funcInfo, ParseNod // Either we are in strict mode, or have strict mode formal semantics from a non-simple parameter list, and && (funcInfo->GetIsStrictMode() || pnodeFnc->sxFnc.HasNonSimpleParameterList()) + // We're not in eval or event handler, which will force the scope(s) to be objects + && !(this->flags & (fscrEval | fscrImplicitThis | fscrImplicitParents)) // Neither of the scopes are objects && !funcInfo->paramScope->GetIsObject() && !funcInfo->bodyScope->GetIsObject();
lib/Runtime/ByteCode/ByteCodeGenerator.h+3 −1 modified@@ -398,10 +398,12 @@ class ByteCodeGenerator Js::FunctionBody *EnsureFakeGlobalFuncForUndefer(ParseNode *pnode); Js::FunctionBody *MakeGlobalFunctionBody(ParseNode *pnode); - static bool NeedScopeObjectForArguments(FuncInfo *funcInfo, ParseNode *pnodeFnc); + bool NeedScopeObjectForArguments(FuncInfo *funcInfo, ParseNode *pnodeFnc) const; void AddFuncInfoToFinalizationSet(FuncInfo *funcInfo); void FinalizeFuncInfos(); + void CheckFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo); + void EnsureFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo); Js::OpCode GetStSlotOp(Scope *scope, int envIndex, Js::RegSlot scopeLocation, bool chkBlockVar, FuncInfo *funcInfo); Js::OpCode GetLdSlotOp(Scope *scope, int envIndex, Js::RegSlot scopeLocation, FuncInfo *funcInfo);
lib/Runtime/ByteCode/ScopeInfo.cpp+7 −7 modified@@ -22,7 +22,7 @@ namespace Js else if (needScopeSlot) { // Any symbol may have non-local ref from deferred child. Allocate slot for it. - scopeSlot = sym->EnsureScopeSlot(mapSymbolData->func); + scopeSlot = sym->EnsureScopeSlot(mapSymbolData->byteCodeGenerator, mapSymbolData->func); } if (needScopeSlot || sym->GetIsModuleExportStorage()) @@ -52,7 +52,7 @@ namespace Js // // Create scope info for a single scope. // - ScopeInfo* ScopeInfo::SaveOneScopeInfo(/*ByteCodeGenerator* byteCodeGenerator, ParseableFunctionInfo* parent,*/ Scope* scope, ScriptContext *scriptContext) + ScopeInfo* ScopeInfo::SaveOneScopeInfo(ByteCodeGenerator* byteCodeGenerator, Scope* scope, ScriptContext *scriptContext) { Assert(scope->GetScopeInfo() == nullptr); Assert(scope->GetScopeType() != ScopeType_Global); @@ -82,7 +82,7 @@ namespace Js scope->GetFunc()->name, count, scopeInfo->isObject ? _u("isObject") : _u("")); - MapSymbolData mapSymbolData = { scope->GetFunc(), 0 }; + MapSymbolData mapSymbolData = { byteCodeGenerator, scope->GetFunc(), 0 }; scope->ForEachSymbol([&mapSymbolData, scopeInfo, scope](Symbol * sym) { Assert(scope == sym->GetScope()); @@ -109,7 +109,7 @@ namespace Js // // Save scope info for an individual scope and link it to its enclosing scope. // - ScopeInfo * ScopeInfo::SaveScopeInfo(Scope * scope/*ByteCodeGenerator* byteCodeGenerator, FuncInfo* parentFunc, FuncInfo* func*/, ScriptContext * scriptContext) + ScopeInfo * ScopeInfo::SaveScopeInfo(ByteCodeGenerator* byteCodeGenerator, Scope * scope, ScriptContext * scriptContext) { // Advance past scopes that will be excluded from the closure environment. (But note that we always want the body scope.) while (scope && (!scope->GetMustInstantiate() && scope != scope->GetFunc()->GetBodyScope())) @@ -131,13 +131,13 @@ namespace Js } // Do the work for this scope. - scopeInfo = ScopeInfo::SaveOneScopeInfo(scope, scriptContext); + scopeInfo = ScopeInfo::SaveOneScopeInfo(byteCodeGenerator, scope, scriptContext); // Link to the parent (if any). scope = scope->GetEnclosingScope(); if (scope) { - scopeInfo->SetParentScopeInfo(ScopeInfo::SaveScopeInfo(scope, scriptContext)); + scopeInfo->SetParentScopeInfo(ScopeInfo::SaveScopeInfo(byteCodeGenerator, scope, scriptContext)); } return scopeInfo; @@ -167,7 +167,7 @@ namespace Js currentScope = currentScope->GetEnclosingScope(); } - ScopeInfo * scopeInfo = ScopeInfo::SaveScopeInfo(currentScope, byteCodeGenerator->GetScriptContext()); + ScopeInfo * scopeInfo = ScopeInfo::SaveScopeInfo(byteCodeGenerator, currentScope, byteCodeGenerator->GetScriptContext()); if (scopeInfo != nullptr) { funcInfo->byteCodeFunction->SetScopeInfo(scopeInfo);
lib/Runtime/ByteCode/ScopeInfo.h+3 −2 modified@@ -15,6 +15,7 @@ namespace Js { struct MapSymbolData { + ByteCodeGenerator *byteCodeGenerator; FuncInfo* func; int nonScopeSymbolCount; }; @@ -181,8 +182,8 @@ namespace Js { void SaveSymbolInfo(Symbol* sym, MapSymbolData* mapSymbolData); - static ScopeInfo* SaveScopeInfo(Scope * scope, ScriptContext * scriptContext); - static ScopeInfo* SaveOneScopeInfo(Scope * scope, ScriptContext * scriptContext); + static ScopeInfo* SaveScopeInfo(ByteCodeGenerator * byteCodeGenerator, Scope * scope, ScriptContext * scriptContext); + static ScopeInfo* SaveOneScopeInfo(ByteCodeGenerator * byteCodeGenerator, Scope * scope, ScriptContext * scriptContext); public: FunctionInfo * GetFunctionInfo() const
lib/Runtime/ByteCode/Symbol.cpp+6 −6 modified@@ -64,18 +64,18 @@ void Symbol::SaveToPropIdArray(Symbol *sym, Js::PropertyIdArray *propIds, ByteCo } } -bool Symbol::NeedsSlotAlloc(FuncInfo *funcInfo) +bool Symbol::NeedsSlotAlloc(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo) { - return IsInSlot(funcInfo, true); + return IsInSlot(byteCodeGenerator, funcInfo, true); } -bool Symbol::IsInSlot(FuncInfo *funcInfo, bool ensureSlotAlloc) +bool Symbol::IsInSlot(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, bool ensureSlotAlloc) { if (this->GetIsGlobal() || this->GetIsModuleExportStorage()) { return false; } - if (funcInfo->GetHasHeapArguments() && this->GetIsFormal() && ByteCodeGenerator::NeedScopeObjectForArguments(funcInfo, funcInfo->root)) + if (funcInfo->GetHasHeapArguments() && this->GetIsFormal() && byteCodeGenerator->NeedScopeObjectForArguments(funcInfo, funcInfo->root)) { return true; } @@ -100,9 +100,9 @@ bool Symbol::GetIsCommittedToSlot() const return isCommittedToSlot || this->scope->GetFunc()->GetCallsEval() || this->scope->GetFunc()->GetChildCallsEval(); } -Js::PropertyId Symbol::EnsureScopeSlot(FuncInfo *funcInfo) +Js::PropertyId Symbol::EnsureScopeSlot(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo) { - if (this->NeedsSlotAlloc(funcInfo) && this->scopeSlot == Js::Constants::NoProperty) + if (this->NeedsSlotAlloc(byteCodeGenerator, funcInfo) && this->scopeSlot == Js::Constants::NoProperty) { this->scopeSlot = this->scope->AddScopeSlot(); }
lib/Runtime/ByteCode/Symbol.h+3 −3 modified@@ -480,9 +480,9 @@ class Symbol return this->name; } - Js::PropertyId EnsureScopeSlot(FuncInfo *funcInfo); - bool IsInSlot(FuncInfo *funcInfo, bool ensureSlotAlloc = false); - bool NeedsSlotAlloc(FuncInfo *funcInfo); + Js::PropertyId EnsureScopeSlot(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo); + bool IsInSlot(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, bool ensureSlotAlloc = false); + bool NeedsSlotAlloc(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo); static void SaveToPropIdArray(Symbol *sym, Js::PropertyIdArray *propIds, ByteCodeGenerator *byteCodeGenerator, Js::PropertyId *pFirstSlot = nullptr);
lib/Runtime/Language/AsmJsModule.cpp+1 −1 modified@@ -124,7 +124,7 @@ namespace Js if (funcInfo->byteCodeFunction->GetIsNamedFunctionExpression()) { Assert(GetModuleFunctionNode()->sxFnc.pnodeName); - if (GetModuleFunctionNode()->sxFnc.pnodeName->sxVar.sym->IsInSlot(funcInfo)) + if (GetModuleFunctionNode()->sxFnc.pnodeName->sxVar.sym->IsInSlot(GetByteCodeGenerator(), funcInfo)) { ParseNodePtr nameNode = GetModuleFunctionNode()->sxFnc.pnodeName; GetByteCodeGenerator()->AssignPropertyId(nameNode->name());
lib/Runtime/Language/InterpreterStackFrame.cpp+14 −4 modified@@ -1296,10 +1296,20 @@ namespace Js // In the debug mode zero out the local slot, so this could prevent locals being uninitialized in the case of setNextStatement. memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount); } - // Zero out only the return slot. This is not a user local, so the byte code will not initialize - // it to "undefined". And it's not an expression temp, so, for instance, a jitted loop body may expect - // it to be valid on entry to the loop, where "valid" means either a var or null. - newInstance->SetNonVarReg(0, NULL); + else + { + Js::RegSlot varCount = function->GetFunctionBody()->GetVarCount(); + if (varCount) + { + // Zero out the non-constant var slots. + Js::RegSlot constantCount = function->GetFunctionBody()->GetConstantCount(); + memset(newInstance->m_localSlots + constantCount, 0, varCount * sizeof(Js::Var)); + } + // Zero out the return slot. This is not a user local, so the byte code will not initialize + // it to "undefined". And it's not an expression temp, so, for instance, a jitted loop body may expect + // it to be valid on entry to the loop, where "valid" means either a var or null. + newInstance->SetNonVarReg(0, NULL); + } #endif // Wasm doesn't use const table if (!executeFunction->IsWasmFunction())
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-25vh-gq6v-hrx5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-0979ghsaADVISORY
- www.securityfocus.com/bid/103625mitrevdb-entryx_refsource_BID
- www.securitytracker.com/id/1040650mitrevdb-entryx_refsource_SECTRACK
- github.com/chakra-core/ChakraCore/commit/26371402f106e81797122f5b4bbd9f5e54bd2553ghsaWEB
- portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-0979ghsax_refsource_CONFIRMWEB
- web.archive.org/web/20210126222855/http://www.securityfocus.com/bid/103625ghsaWEB
- web.archive.org/web/20211207123630/http://www.securitytracker.com/id/1040650ghsaWEB
News mentions
0No linked articles in our index yet.