VYPR
High severityNVD Advisory· Published May 16, 2019· Updated Aug 4, 2024

CVE-2019-0925

CVE-2019-0925

Description

Chakra scripting engine memory corruption in Microsoft Edge allows remote code execution through a crafted website.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Chakra scripting engine memory corruption in Microsoft Edge allows remote code execution through a crafted website.

Vulnerability

A remote code execution vulnerability exists in the Chakra scripting engine used by Microsoft Edge. It is a memory corruption bug in the way the engine handles objects in memory, specifically in the GlobOpt::ProcessFieldKills function within the global optimization phase of the JIT compiler. The issue affects ChakraCore versions prior to the fix; the patch introduces proper handling of several opcodes including StElemC, ScopedDeleteFld, ScopedDeleteFldStrict, ConsoleScopedStFld, ConsoleScopedStFldStrict, ScopedStFld, ScopedStFldStrict, InitConstFld, InitLetFld, InitRootFld, InitRootConstFld, InitRootLetFld, StSlotBoxTemp, StSuperFld, and NewScObjectNoCtorFull. These opcodes were missing from the kill set, potentially allowing type confusion and memory corruption. The vulnerability affects Microsoft Edge (EdgeHTML-based) and any application embedding ChakraCore before the patch [1][2][3].

Exploitation

An attacker could host a specially crafted website that triggers the vulnerability when visited using Microsoft Edge. No additional privileges or user interaction beyond browsing the site is required. The attacker would need to craft JavaScript that causes the Chakra engine to execute a sequence of opcodes that bypass the field kill logic in GlobOpt::ProcessFieldKills, leading to memory corruption. The fix ensures that these opcodes are properly handled to invalidate type assumptions, preventing the exploitation path [1][2][3].

Impact

Successful exploitation allows an attacker to execute arbitrary code in the context of the current user. This could lead to full compromise of the affected system, including installation of programs, viewing, changing, or deleting data, or creating new accounts with full user rights. The vulnerability is rated as Critical with a CVSS v3 score not provided in the references, but the remote code execution impact is severe [1].

Mitigation

Microsoft released a security update in May 2019 to address this vulnerability. The fix is included in the cumulative update for Microsoft Edge and also patched in the ChakraCore repository via commits [2] and [3]. Users should apply the latest updates from Microsoft Update or Windows Update. There is no publicly known workaround other than upgrading to a patched version. This CVE is not listed in the KEV catalog.

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.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.11.91.11.9

Affected products

6
  • ghsa-coords
    Range: < 1.11.9
  • Range: unspecified
  • Microsoft/Edgecpe-rescue
    Range: Windows Server 2016
  • Microsoft/Microsoft Edge on Windows 10 Version 1903 for 32-bit Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge on Windows 10 Version 1903 for ARM64-based Systemsv5
    Range: unspecified
  • Microsoft/Microsoft Edge on Windows 10 Version 1903 for x64-based Systemsv5
    Range: unspecified

Patches

2
d797e3f00e34

[MERGE #6122 @MikeHolman] May 2019 Security Update

https://github.com/chakra-core/ChakraCoreMichael HolmanMay 14, 2019via ghsa
18 files changed · +182 38
  • Build/NuGet/.pack-version+1 1 modified
    @@ -1 +1 @@
    -1.11.8
    +1.11.9
    
  • lib/Backend/BackwardPass.cpp+1 2 modified
    @@ -4677,10 +4677,9 @@ BackwardPass::ProcessNewScObject(IR::Instr* instr)
             return;
         }
     
    -    if (instr->HasBailOutInfo())
    +    if (instr->HasBailOutInfo() && (instr->GetBailOutKind() & ~IR::BailOutKindBits) == IR::BailOutFailedCtorGuardCheck)
         {
             Assert(instr->IsProfiledInstr());
    -        Assert(instr->GetBailOutKind() == IR::BailOutFailedCtorGuardCheck);
             Assert(instr->GetDst()->IsRegOpnd());
     
             BasicBlock * block = this->currentBlock;
    
  • lib/Backend/GlobOptArrays.cpp+8 1 modified
    @@ -1736,7 +1736,14 @@ void GlobOpt::ArraySrcOpt::Optimize()
         {
             if (newBaseValueType != baseValueType)
             {
    -            UpdateValue(nullptr, nullptr, nullptr);
    +            if (globOpt->IsSafeToTransferInPrePass(baseOpnd, baseValue))
    +            {
    +                UpdateValue(nullptr, nullptr, nullptr);
    +            }
    +            else if (isLikelyJsArray && globOpt->IsOperationThatLikelyKillsJsArraysWithNoMissingValues(instr) && baseValueInfo->HasNoMissingValues())
    +            {
    +                globOpt->ChangeValueType(nullptr, baseValue, baseValueInfo->Type().SetHasNoMissingValues(false), true);
    +            }
             }
     
             // For javascript arrays and objects with javascript arrays:
    
  • lib/Backend/GlobOptBailOut.cpp+8 0 modified
    @@ -1337,6 +1337,14 @@ GlobOpt::MayNeedBailOnImplicitCall(IR::Instr const * instr, Value const * src1Va
                 );
         }
     
    +    case Js::OpCode::NewScObjectNoCtor:
    +        if (instr->HasBailOutInfo() && (instr->GetBailOutKind() & ~IR::BailOutKindBits) == IR::BailOutFailedCtorGuardCheck)
    +        {
    +            // No helper call with this bailout.
    +            return false;
    +        }
    +        break;
    +
         default:
             break;
         }
    
  • lib/Backend/GlobOpt.cpp+7 0 modified
    @@ -13199,6 +13199,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
         const bool useValueTypes = !IsLoopPrePass(); // Source value types are not guaranteed to be correct in a loop prepass
         switch(instr->m_opcode)
         {
    +        case Js::OpCode::StElemC:
             case Js::OpCode::StElemI_A:
             case Js::OpCode::StElemI_A_Strict:
             {
    @@ -13249,8 +13250,13 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
                 }
                 break;
     
    +        case Js::OpCode::ConsoleScopedStFld:
    +        case Js::OpCode::ConsoleScopedStFldStrict:
    +        case Js::OpCode::ScopedStFld:
    +        case Js::OpCode::ScopedStFldStrict:
             case Js::OpCode::StFld:
             case Js::OpCode::StFldStrict:
    +        case Js::OpCode::StSuperFld:
             {
                 Assert(instr->GetDst());
     
    @@ -13462,6 +13468,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
                 break;
     
             case Js::OpCode::NewScObjectNoCtor:
    +        case Js::OpCode::NewScObjectNoCtorFull:
                 if(doNativeArrayTypeSpec)
                 {
                     // Class/object construction can make something a prototype
    
  • lib/Backend/GlobOptExpr.cpp+8 0 modified
    @@ -814,20 +814,28 @@ GlobOpt::ProcessArrayValueKills(IR::Instr *instr)
     {
         switch (instr->m_opcode)
         {
    +    case Js::OpCode::StElemC:
         case Js::OpCode::StElemI_A:
         case Js::OpCode::StElemI_A_Strict:
         case Js::OpCode::DeleteElemI_A:
         case Js::OpCode::DeleteElemIStrict_A:
    +    case Js::OpCode::ConsoleScopedStFld:
    +    case Js::OpCode::ConsoleScopedStFldStrict:
    +    case Js::OpCode::ScopedStFld:
    +    case Js::OpCode::ScopedStFldStrict:
         case Js::OpCode::StFld:
         case Js::OpCode::StRootFld:
         case Js::OpCode::StFldStrict:
         case Js::OpCode::StRootFldStrict:
    +    case Js::OpCode::StSuperFld:
         case Js::OpCode::StSlot:
         case Js::OpCode::StSlotChkUndecl:
         case Js::OpCode::DeleteFld:
         case Js::OpCode::DeleteRootFld:
         case Js::OpCode::DeleteFldStrict:
         case Js::OpCode::DeleteRootFldStrict:
    +    case Js::OpCode::ScopedDeleteFld:
    +    case Js::OpCode::ScopedDeleteFldStrict:
         case Js::OpCode::StArrViewElem:
         // These array helpers may change A.length (and A[i] could be A.length)...
         case Js::OpCode::InlineArrayPush:
    
  • lib/Backend/GlobOptFields.cpp+51 7 modified
    @@ -335,6 +335,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
         IR::JnHelperMethod fnHelper;
         switch(instr->m_opcode)
         {
    +    case Js::OpCode::StElemC:
         case Js::OpCode::StElemI_A:
         case Js::OpCode::StElemI_A_Strict:
             Assert(dstOpnd != nullptr);
    @@ -366,6 +367,8 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
         case Js::OpCode::DeleteRootFld:
         case Js::OpCode::DeleteFldStrict:
         case Js::OpCode::DeleteRootFldStrict:
    +    case Js::OpCode::ScopedDeleteFld:
    +    case Js::OpCode::ScopedDeleteFldStrict:
             sym = instr->GetSrc1()->AsSymOpnd()->m_sym;
             KillLiveFields(sym->AsPropertySym(), bv);
             if (inGlobOpt)
    @@ -387,13 +390,36 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
                 this->KillAllObjectTypes(bv);
             }
             break;
    +
    +    case Js::OpCode::ConsoleScopedStFld:
    +    case Js::OpCode::ConsoleScopedStFldStrict:
    +    case Js::OpCode::ScopedStFld:
    +    case Js::OpCode::ScopedStFldStrict:
    +        // This is already taken care of for FastFld opcodes
    +
    +        if (inGlobOpt)
    +        {
    +            KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
    +        }
    +
    +        // fall through
    +
         case Js::OpCode::InitFld:
    +    case Js::OpCode::InitConstFld:
    +    case Js::OpCode::InitLetFld:
    +    case Js::OpCode::InitRootFld:
    +    case Js::OpCode::InitRootConstFld:
    +    case Js::OpCode::InitRootLetFld:
    +#if !FLOATVAR
    +    case Js::OpCode::StSlotBoxTemp:
    +#endif
         case Js::OpCode::StFld:
         case Js::OpCode::StRootFld:
         case Js::OpCode::StFldStrict:
         case Js::OpCode::StRootFldStrict:
         case Js::OpCode::StSlot:
         case Js::OpCode::StSlotChkUndecl:
    +    case Js::OpCode::StSuperFld:
             Assert(dstOpnd != nullptr);
             sym = dstOpnd->AsSymOpnd()->m_sym;
             if (inGlobOpt)
    @@ -415,11 +441,19 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
     
         case Js::OpCode::InlineArrayPush:
         case Js::OpCode::InlineArrayPop:
    -        KillLiveFields(this->lengthEquivBv, bv);
    -        if (inGlobOpt)
    +        if(instr->m_func->GetThisOrParentInlinerHasArguments())
             {
    -            // Deleting an item, or pushing a property to a non-array, may change object layout
    -            KillAllObjectTypes(bv);
    +            this->KillAllFields(bv);
    +            this->SetAnyPropertyMayBeWrittenTo();
    +        }
    +        else
    +        {
    +            KillLiveFields(this->lengthEquivBv, bv);
    +            if (inGlobOpt)
    +            {
    +                // Deleting an item, or pushing a property to a non-array, may change object layout
    +                KillAllObjectTypes(bv);
    +            }
             }
             break;
     
    @@ -444,14 +478,23 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
                     // Kill length field for built-ins that can update it.
                     if (nullptr != this->lengthEquivBv)
                     {
    -                    KillLiveFields(this->lengthEquivBv, bv);
    +                    // If has arguments, all fields are killed in fall through
    +                    if (!instr->m_func->GetThisOrParentInlinerHasArguments())
    +                    {
    +                        KillLiveFields(this->lengthEquivBv, bv);
    +                    }
                     }
                     // fall through
     
                 case IR::JnHelperMethod::HelperArray_Reverse:
    -                // Deleting an item may change object layout
    -                if (inGlobOpt)
    +                if (instr->m_func->GetThisOrParentInlinerHasArguments())
    +                {
    +                    this->KillAllFields(bv);
    +                    this->SetAnyPropertyMayBeWrittenTo();
    +                }
    +                else if (inGlobOpt)
                     {
    +                    // Deleting an item may change object layout
                         KillAllObjectTypes(bv);
                     }
                     break;
    @@ -492,6 +535,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
         case Js::OpCode::InitClass:
         case Js::OpCode::InitProto:
         case Js::OpCode::NewScObjectNoCtor:
    +    case Js::OpCode::NewScObjectNoCtorFull:
             if (inGlobOpt)
             {
                 // Opcodes that make an object into a prototype may break object-header-inlining and final type opt.
    
  • lib/Backend/Inline.cpp+2 0 modified
    @@ -4204,6 +4204,8 @@ Inline::SplitConstructorCallCommon(
         {
             createObjInstr->SetByteCodeOffset(newObjInstr);
             createObjInstr->GetSrc1()->SetIsJITOptimizedReg(true);
    +        // We're splitting a single byte code, so the interpreter has to resume from the beginning if we bail out.
    +        createObjInstr->forcePreOpBailOutIfNeeded = true;
             newObjInstr->InsertBefore(createObjInstr);
     
             createObjDst->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
    
  • lib/Backend/IRBuilder.cpp+2 2 modified
    @@ -1758,7 +1758,7 @@ IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0)
             }
     
         case Js::OpCode::NewScObjectSimple:
    -        dstValueType = ValueType::GetObject(ObjectType::Object);
    +        dstValueType = ValueType::GetObject(ObjectType::UninitializedObject);
             // fall-through
         case Js::OpCode::LdFuncExpr:
             m_func->DisableCanDoInlineArgOpt();
    @@ -5050,7 +5050,7 @@ IRBuilder::BuildAuxiliary(Js::OpCode newOpcode, uint32 offset)
                 // lower take it from there...
                 srcOpnd = IR::IntConstOpnd::New(auxInsn->Offset, TyUint32, m_func);
                 dstOpnd = this->BuildDstOpnd(dstRegSlot);
    -            dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Object));
    +            dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
                 instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
     
                 // Because we're going to be making decisions based off the value, we have to defer
    
  • lib/Backend/Lower.cpp+32 14 modified
    @@ -4601,18 +4601,40 @@ Lowerer::LowerNewScObject(IR::Instr *newObjInstr, bool callCtor, bool hasArgs, b
             {
                 Assert(!newObjDst->CanStoreTemp());
                 // createObjDst = NewScObject...(ctorOpnd)
    -            newScHelper = !callCtor ?
    -                (isBaseClassConstructorNewScObject ?
    -                    (hasArgs ? IR::HelperNewScObjectNoCtorFull : IR::HelperNewScObjectNoArgNoCtorFull) :
    -                    (hasArgs ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArgNoCtor)) :
    -                (hasArgs || usedFixedCtorCache ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArg);
     
                 LoadScriptContext(newObjInstr);
    -            m_lowererMD.LoadHelperArgument(newObjInstr, newObjInstr->GetSrc1());
     
    -            newScObjCall = IR::Instr::New(Js::OpCode::Call, createObjDst, IR::HelperCallOpnd::New(newScHelper, func), func);
    -            newObjInstr->InsertBefore(newScObjCall);
    -            m_lowererMD.LowerCall(newScObjCall, 0);
    +            if (callCtor)
    +            {
    +                newScHelper = (hasArgs || usedFixedCtorCache ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArg);
    +
    +                m_lowererMD.LoadHelperArgument(newObjInstr, newObjInstr->GetSrc1());
    +
    +                newScObjCall = IR::Instr::New(Js::OpCode::Call, createObjDst, IR::HelperCallOpnd::New(newScHelper, func), func);
    +                newObjInstr->InsertBefore(newScObjCall);
    +                m_lowererMD.LowerCall(newScObjCall, 0);
    +            }
    +            else
    +            {
    +                newScHelper = 
    +                    (isBaseClassConstructorNewScObject ?
    +                        (hasArgs ? IR::HelperNewScObjectNoCtorFull : IR::HelperNewScObjectNoArgNoCtorFull) :
    +                        (hasArgs ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArgNoCtor));
    +
    +                // Branch around the helper call to execute the inlined ctor.
    +                Assert(callCtorLabel != nullptr);
    +                newObjInstr->InsertAfter(callCtorLabel);
    +
    +                // Change the NewScObject* to a helper call on the spot. This generates implicit call bailout for us if we need one.
    +                m_lowererMD.LoadHelperArgument(newObjInstr, newObjInstr->UnlinkSrc1());
    +                m_lowererMD.ChangeToHelperCall(newObjInstr, newScHelper);
    +
    +                // Then we're done.
    +                Assert(createObjDst == newObjDst);
    +
    +                // Return the first instruction above the region we've just lowered.
    +                return RemoveLoweredRegionStartMarker(startMarkerInstr);                    
    +            }
             }
         }
     
    @@ -4857,21 +4879,17 @@ bool Lowerer::TryLowerNewScObjectWithFixedCtorCache(IR::Instr* newObjInstr, IR::
         skipNewScObj = false;
         returnNewScObj = false;
     
    -    AssertMsg(!PHASE_OFF(Js::ObjTypeSpecNewObjPhase, this->m_func) || !newObjInstr->HasBailOutInfo(),
    -        "Why do we have bailout on NewScObject when ObjTypeSpecNewObj is off?");
    -
         if (PHASE_OFF(Js::FixedNewObjPhase, newObjInstr->m_func) && PHASE_OFF(Js::ObjTypeSpecNewObjPhase, this->m_func))
         {
             return false;
         }
     
         JITTimeConstructorCache * ctorCache;
     
    -    if (newObjInstr->HasBailOutInfo())
    +    if (newObjInstr->HasBailOutInfo() && (newObjInstr->GetBailOutKind() & ~IR::BailOutKindBits) == IR::BailOutFailedCtorGuardCheck)
         {
             Assert(newObjInstr->IsNewScObjectInstr());
             Assert(newObjInstr->IsProfiledInstr());
    -        Assert(newObjInstr->GetBailOutKind() == IR::BailOutFailedCtorGuardCheck);
     
             emitBailOut = true;
     
    
  • lib/Common/ChakraCoreVersion.h+1 1 modified
    @@ -17,7 +17,7 @@
     // ChakraCore version number definitions (used in ChakraCore binary metadata)
     #define CHAKRA_CORE_MAJOR_VERSION 1
     #define CHAKRA_CORE_MINOR_VERSION 11
    -#define CHAKRA_CORE_PATCH_VERSION 8
    +#define CHAKRA_CORE_PATCH_VERSION 9
     #define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0.
     
     // -------------
    
  • lib/Runtime/ByteCode/ByteCodeEmitter.cpp+11 0 modified
    @@ -3590,6 +3590,7 @@ void ByteCodeGenerator::StartEmitFunction(ParseNodeFnc *pnodeFnc)
     #if ENABLE_TTD
                         && !funcInfo->GetParsedFunctionBody()->GetScriptContext()->GetThreadContext()->IsRuntimeInTTDMode()
     #endif
    +                    && !funcInfo->byteCodeFunction->IsCoroutine()
                     );
     
                     if (funcInfo->GetHasCachedScope())
    @@ -4005,6 +4006,11 @@ void ByteCodeGenerator::StartEmitCatch(ParseNodeCatch *pnodeCatch)
                     sym->SetIsGlobalCatch(true);
                 }
     
    +            if (sym->NeedsScopeObject())
    +            {
    +                scope->SetIsObject();
    +            }
    +
                 Assert(sym->GetScopeSlot() == Js::Constants::NoProperty);
                 if (sym->NeedsSlotAlloc(this, funcInfo))
                 {
    @@ -4028,6 +4034,11 @@ void ByteCodeGenerator::StartEmitCatch(ParseNodeCatch *pnodeCatch)
                 sym->SetIsGlobalCatch(true);
             }
     
    +        if (sym->NeedsScopeObject())
    +        {
    +            scope->SetIsObject();
    +        }
    +
             if (scope->GetMustInstantiate())
             {
                 if (sym->IsInSlot(this, funcInfo))
    
  • lib/Runtime/ByteCode/ByteCodeGenerator.cpp+6 6 modified
    @@ -119,10 +119,10 @@ void EndVisitBlock(ParseNodeBlock *pnode, ByteCodeGenerator *byteCodeGenerator)
             Scope *scope = pnode->scope;
             FuncInfo *func = scope->GetFunc();
     
    -        if (!byteCodeGenerator->IsInDebugMode() &&
    -            scope->HasInnerScopeIndex())
    +        if (!(byteCodeGenerator->IsInDebugMode() || func->byteCodeFunction->IsCoroutine())
    +            && scope->HasInnerScopeIndex())
             {
    -            // In debug mode, don't release the current index, as we're giving each scope a unique index, regardless
    +            // In debug mode (or for the generator/async function), don't release the current index, as we're giving each scope a unique index, regardless
                 // of nesting.
                 Assert(scope->GetInnerScopeIndex() == func->CurrentInnerScopeIndex());
                 func->ReleaseInnerScopeIndex();
    @@ -155,12 +155,12 @@ void BeginVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
     void EndVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
     {
         Scope *scope = pnode->AsParseNodeCatch()->scope;
    +    FuncInfo *func = scope->GetFunc();
     
    -    if (scope->HasInnerScopeIndex() && !byteCodeGenerator->IsInDebugMode())
    +    if (scope->HasInnerScopeIndex() && !(byteCodeGenerator->IsInDebugMode() || func->byteCodeFunction->IsCoroutine()))
         {
    -        // In debug mode, don't release the current index, as we're giving each scope a unique index,
    +        // In debug mode (or for the generator/async function), don't release the current index, as we're giving each scope a unique index,
             // regardless of nesting.
    -        FuncInfo *func = scope->GetFunc();
     
             Assert(scope->GetInnerScopeIndex() == func->CurrentInnerScopeIndex());
             func->ReleaseInnerScopeIndex();
    
  • lib/Runtime/ByteCode/OpCodes.h+2 2 modified
    @@ -577,8 +577,8 @@ MACRO_EXTEND_WMS_AND_PROFILED(NewScObjectSpread,   CallIExtended, OpSideEffect|O
     MACRO_WMS_PROFILED2(    NewScObjArray,      CallI,          OpSideEffect|OpUseAllFields|OpCallInstr)        // Create new ScriptObject instance
     MACRO_WMS_PROFILED2(    NewScObjArraySpread, CallIExtended, OpSideEffect|OpUseAllFields|OpCallInstr)        // Create new ScriptObject instance
     MACRO(                  NewScObject_A,      Auxiliary,      OpSideEffect|OpUseAllFields)                    // Create new ScriptObject instance passing only constants
    -MACRO_WMS(              NewScObjectNoCtorFull, Reg2,        OpTempObjectCanStoreTemp)                       // Create new object that will be used for the 'this' binding in a base class constructor
    -MACRO_BACKEND_ONLY(     NewScObjectNoCtor,  Empty,          OpTempObjectCanStoreTemp)                       // Create new object that will be passed into a constructor
    +MACRO_WMS(              NewScObjectNoCtorFull, Reg2,        OpTempObjectCanStoreTemp|OpHasImplicitCall)     // Create new object that will be used for the 'this' binding in a base class constructor
    +MACRO_BACKEND_ONLY(     NewScObjectNoCtor,  Empty,          OpTempObjectCanStoreTemp|OpHasImplicitCall)     // Create new object that will be passed into a constructor
     MACRO_BACKEND_ONLY(     GetNewScObject,     Empty,          OpTempObjectTransfer)                           // Determine which object to finally use as the result of NewScObject (object passed into constructor as 'this', or object returned by constructor)
     MACRO_BACKEND_ONLY(     UpdateNewScObjectCache, Empty,      None)                                           // Update the cache used for NewScObject
     MACRO_WMS(              NewScObjectSimple,  Reg1,           OpTempObjectCanStoreTemp)
    
  • lib/Runtime/Debug/DebugContext.cpp+33 1 modified
    @@ -193,6 +193,11 @@ namespace Js
             Js::TempArenaAllocatorObject *tempAllocator = nullptr;
             JsUtil::List<Js::FunctionInfo *, Recycler>* pFunctionsToRegister = nullptr;
             JsUtil::List<Js::Utf8SourceInfo *, Recycler, false, Js::CopyRemovePolicy, RecyclerPointerComparer>* utf8SourceInfoList = nullptr;
    +        typedef JsUtil::BaseDictionary<uint32, RegSlot, ArenaAllocator, PowerOf2SizePolicy> FunctionStartToYieldRegister;
    +
    +        // This container ensures that for Generator/Async functions the yield register is same between non-debug to debug parse.
    +        // Each entry represent a function's start position (each function will have unique start position in a file) and that function yield register
    +        FunctionStartToYieldRegister *yieldFunctions = nullptr;
     
             HRESULT hr = S_OK;
             ThreadContext* threadContext = this->scriptContext->GetThreadContext();
    @@ -201,6 +206,7 @@ namespace Js
             tempAllocator = threadContext->GetTemporaryAllocator(_u("debuggerAlloc"));
     
             utf8SourceInfoList = JsUtil::List<Js::Utf8SourceInfo *, Recycler, false, Js::CopyRemovePolicy, RecyclerPointerComparer>::New(this->scriptContext->GetRecycler());
    +        yieldFunctions = Anew(tempAllocator->GetAllocator(), FunctionStartToYieldRegister, tempAllocator->GetAllocator());
     
             this->MapUTF8SourceInfoUntil([&](Js::Utf8SourceInfo * sourceInfo) -> bool
             {
    @@ -276,6 +282,23 @@ namespace Js
                     this->hostDebugContext->SetThreadDescription(sourceInfo->GetSourceContextInfo()->url); // the HRESULT is omitted.
                 }
     
    +            if (shouldReparseFunctions)
    +            {
    +                yieldFunctions->Clear();
    +                BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED
    +                {
    +                    sourceInfo->MapFunction([&](Js::FunctionBody *const pFuncBody)
    +                    {
    +                        if (pFuncBody->IsCoroutine() && pFuncBody->GetYieldRegister() != Js::Constants::NoRegister)
    +                        {
    +                            yieldFunctions->Add(pFuncBody->StartInDocument(), pFuncBody->GetYieldRegister());
    +                        }
    +                    });
    +                }
    +                END_TRANSLATE_OOM_TO_HRESULT(hr);
    +                DEBUGGER_ATTACHDETACH_FATAL_ERROR_IF_FAILED(hr);
    +            }
    +
                 bool fHasDoneSourceRundown = false;
                 for (int i = 0; i < pFunctionsToRegister->Count(); i++)
                 {
    @@ -326,8 +349,17 @@ namespace Js
     
                 if (shouldReparseFunctions)
                 {
    -                sourceInfo->MapFunction([](Js::FunctionBody *const pFuncBody)
    +                sourceInfo->MapFunction([&](Js::FunctionBody *const pFuncBody)
                     {
    +                    if (pFuncBody->IsCoroutine())
    +                    {
    +                        RegSlot oldYieldRegister = Constants::NoRegister;
    +                        if (yieldFunctions->TryGetValue(pFuncBody->StartInDocument(), &oldYieldRegister))
    +                        {
    +                            AssertOrFailFast(pFuncBody->GetYieldRegister() == oldYieldRegister);
    +                        }
    +                    }
    +
                         if (pFuncBody->IsFunctionParsed())
                         {
                             pFuncBody->ReinitializeExecutionModeAndLimits();
    
  • lib/Runtime/Language/ValueType.cpp+2 1 modified
    @@ -577,7 +577,8 @@ bool ValueType::IsNotArrayOrObjectWithArray() const
     {
         return
             IsNotObject() ||
    -        (IsObject() && GetObjectType() != ObjectType::ObjectWithArray && GetObjectType() != ObjectType::Array);
    +        (IsObject() && GetObjectType() != ObjectType::ObjectWithArray && GetObjectType() != ObjectType::Array
    +         && GetObjectType() != ObjectType::UninitializedObject && GetObjectType() != ObjectType::Object);
     }
     
     bool ValueType::IsNativeArray() const
    
  • lib/Runtime/Library/ES5Array.cpp+4 0 modified
    @@ -148,6 +148,10 @@ namespace Js
                 {
                     JavascriptError::ThrowRangeError(scriptContext, JSERR_ArrayLengthAssignIncorrect);
                 }
    +
    +            // Conversion can change the type (e.g. from String), invalidating assumptions made by the JIT
    +            scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
    +
                 return newLen;
             }
         }
    
  • lib/Runtime/Library/JavascriptArray.cpp+3 0 modified
    @@ -2930,6 +2930,9 @@ using namespace Js;
             double dblValue = JavascriptConversion::ToNumber(newLength, scriptContext);
             if (dblValue == uintValue)
             {
    +            // Conversion can change the type (e.g. from String), invalidating assumptions made by the JIT
    +            scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
    +
                 this->SetLength(uintValue);
             }
             else
    
32ca10f3955f

[CVE-2019-0925]

https://github.com/chakra-core/ChakraCorePaul LeathersApr 17, 2019via ghsa
2 files changed · +2 0
  • lib/Backend/GlobOpt.cpp+1 0 modified
    @@ -13462,6 +13462,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
                 break;
     
             case Js::OpCode::NewScObjectNoCtor:
    +        case Js::OpCode::NewScObjectNoCtorFull:
                 if(doNativeArrayTypeSpec)
                 {
                     // Class/object construction can make something a prototype
    
  • lib/Backend/GlobOptFields.cpp+1 0 modified
    @@ -492,6 +492,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
         case Js::OpCode::InitClass:
         case Js::OpCode::InitProto:
         case Js::OpCode::NewScObjectNoCtor:
    +    case Js::OpCode::NewScObjectNoCtorFull:
             if (inGlobOpt)
             {
                 // Opcodes that make an object into a prototype may break object-header-inlining and final type opt.
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.