VYPR
High severityNVD Advisory· Published Jul 15, 2019· Updated Aug 4, 2024

CVE-2019-1092

CVE-2019-1092

Description

A memory corruption vulnerability in ChakraCore's JIT compiler due to improper array bounds handling can allow remote code execution in Microsoft Edge.

AI Insight

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

A memory corruption vulnerability in ChakraCore's JIT compiler due to improper array bounds handling can allow remote code execution in Microsoft Edge.

Vulnerability

Analysis

CVE-2019-1092 is a remote code execution vulnerability in the Chakra scripting engine used by Microsoft Edge. The root cause lies in the Just-In-Time (JIT) compiler's incorrect handling of array value information merging during compilation, leading to an out-of-bounds read/write condition [1][3]. This flaw allows an attacker to corrupt memory and potentially execute arbitrary code.

Exploitation

The attack surface is limited to users browsing the web with Microsoft Edge. An attacker can host a malicious website containing crafted JavaScript that triggers the vulnerable code path. No additional authentication or network position is required beyond standard web browsing [2].

Impact

Successful exploitation enables an attacker to run arbitrary code in the context of the current user. This could result in installation of malware, data theft, or complete compromise of the affected system [2].

Mitigation

Microsoft released a security update in July 2019 that addresses this vulnerability. Users are advised to apply the latest patches to Microsoft Edge or upgrade to a supported browser. The fix is also available in the ChakraCore open-source repository [1].

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.111.11.11

Affected products

6
  • ghsa-coords
    Range: < 1.11.11
  • Range: unspecified
  • Microsoft/Edgecpe-rescue
    Range: Windows 10 for 32-bit Systems
  • 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

3
75162b7f2d8a

[MERGE #6196 @atulkatti] ChakraCore servicing update for July, 2019

https://github.com/microsoft/chakracoreAtul KattiJul 9, 2019via osv
16 files changed · +81 27
  • Build/NuGet/.pack-version+1 1 modified
    @@ -1 +1 @@
    -1.11.10
    +1.11.11
    
  • lib/Backend/BackwardPass.cpp+8 4 modified
    @@ -4151,13 +4151,17 @@ BackwardPass::UpdateImplicitCallBailOutKind(IR::Instr *const instr, bool needsBa
     
         IR::BailOutKind implicitCallBailOutKind = needsBailOutOnImplicitCall ? IR::BailOutOnImplicitCalls : IR::BailOutInvalid;
     
    -    const IR::BailOutKind instrBailOutKind = instr->GetBailOutKind();
    +    IR::BailOutKind instrBailOutKind = instr->GetBailOutKind();
         if (instrBailOutKind & IR::BailOutMarkTempObject)
         {
    -        // Don't remove the implicit call pre op bailout for mark temp object
             // Remove the mark temp object bit, as we don't need it after the dead store pass
    -        instr->SetBailOutKind(instrBailOutKind & ~IR::BailOutMarkTempObject);
    -        return true;
    +        instrBailOutKind &= ~IR::BailOutMarkTempObject;
    +        instr->SetBailOutKind(instrBailOutKind);
    +
    +        if (!instr->GetBailOutInfo()->canDeadStore)
    +        {
    +            return true;
    +        }
         }
     
         const IR::BailOutKind instrImplicitCallBailOutKind = instrBailOutKind & ~IR::BailOutKindBits;
    
  • lib/Backend/BailOut.h+2 1 modified
    @@ -27,7 +27,7 @@ class BailOutInfo
         BailOutInfo(uint32 bailOutOffset, Func* bailOutFunc) :
             bailOutOffset(bailOutOffset), bailOutFunc(bailOutFunc),
             byteCodeUpwardExposedUsed(nullptr), polymorphicCacheIndex((uint)-1), startCallCount(0), startCallInfo(nullptr), bailOutInstr(nullptr),
    -        totalOutParamCount(0), argOutSyms(nullptr), bailOutRecord(nullptr), wasCloned(false), isInvertedBranch(false), sharedBailOutKind(true), isLoopTopBailOutInfo(false),
    +        totalOutParamCount(0), argOutSyms(nullptr), bailOutRecord(nullptr), wasCloned(false), isInvertedBranch(false), sharedBailOutKind(true), isLoopTopBailOutInfo(false), canDeadStore(true),
             outParamInlinedArgSlot(nullptr), liveVarSyms(nullptr), liveLosslessInt32Syms(nullptr), liveFloat64Syms(nullptr),
             branchConditionOpnd(nullptr),
             stackLiteralBailOutInfoCount(0), stackLiteralBailOutInfo(nullptr)
    @@ -69,6 +69,7 @@ class BailOutInfo
     #endif
         bool wasCloned;
         bool isInvertedBranch;
    +    bool canDeadStore;
         bool sharedBailOutKind;
         bool isLoopTopBailOutInfo;
     
    
  • lib/Backend/Func.cpp+9 0 modified
    @@ -345,6 +345,9 @@ Func::Codegen(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
                 case RejitReason::TrackIntOverflowDisabled:
                     outputData->disableTrackCompoundedIntOverflow = TRUE;
                     break;
    +            case RejitReason::MemOpDisabled:
    +                outputData->disableMemOp = TRUE;
    +                break;
                 default:
                     Assume(UNREACHED);
                 }
    @@ -1124,6 +1127,12 @@ Func::IsTrackCompoundedIntOverflowDisabled() const
         return (HasProfileInfo() && GetReadOnlyProfileInfo()->IsTrackCompoundedIntOverflowDisabled()) || m_output.IsTrackCompoundedIntOverflowDisabled();
     }
     
    +bool
    +Func::IsMemOpDisabled() const
    +{
    +    return (HasProfileInfo() && GetReadOnlyProfileInfo()->IsMemOpDisabled()) || m_output.IsMemOpDisabled();
    +}
    +
     bool
     Func::IsArrayCheckHoistDisabled() const
     {
    
  • lib/Backend/Func.h+1 0 modified
    @@ -995,6 +995,7 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
         void SetScopeObjSym(StackSym * sym);
         StackSym * GetScopeObjSym();
         bool IsTrackCompoundedIntOverflowDisabled() const;
    +    bool IsMemOpDisabled() const;
         bool IsArrayCheckHoistDisabled() const;
         bool IsStackArgOptDisabled() const;
         bool IsSwitchOptDisabled() const;
    
  • lib/Backend/GlobOptBlockData.cpp+7 5 modified
    @@ -974,7 +974,8 @@ GlobOptBlockData::MergeValueInfo(
                     fromDataValueInfo->AsArrayValueInfo(),
                     fromDataSym,
                     symsRequiringCompensation,
    -                symsCreatedForMerge);
    +                symsCreatedForMerge,
    +                isLoopBackEdge);
         }
     
         // Consider: If both values are VarConstantValueInfo with the same value, we could
    @@ -1072,7 +1073,8 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
         const ArrayValueInfo *const fromDataValueInfo,
         Sym *const arraySym,
         BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
    -    BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
    +    BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
    +    bool isLoopBackEdge)
     {
         Assert(mergedValueType.IsAnyOptimizedArray());
         Assert(toDataValueInfo);
    @@ -1095,7 +1097,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     // Adding compensation code in the prepass won't help, as the symstores would again be different in the main pass.
                     Assert(symsRequiringCompensation);
    @@ -1123,7 +1125,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     Assert(symsRequiringCompensation);
                     symsRequiringCompensation->Set(arraySym->m_id);
    @@ -1150,7 +1152,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     Assert(symsRequiringCompensation);
                     symsRequiringCompensation->Set(arraySym->m_id);
    
  • lib/Backend/GlobOptBlockData.h+1 1 modified
    @@ -264,7 +264,7 @@ class GlobOptBlockData
         Value *                 MergeValues(Value *toDataValue, Value *fromDataValue, Sym *fromDataSym, bool isLoopBackEdge, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
         ValueInfo *             MergeValueInfo(Value *toDataVal, Value *fromDataVal, Sym *fromDataSym, bool isLoopBackEdge, bool sameValueNumber, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
         JsTypeValueInfo *       MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber);
    -    ValueInfo *             MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
    +    ValueInfo *             MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge, bool isLoopBackEdge);
     
         // Argument Tracking
     public:
    
  • lib/Backend/GlobOpt.cpp+15 2 modified
    @@ -2624,7 +2624,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
             !(instr->IsJitProfilingInstr()) &&
             this->currentBlock->loop && !IsLoopPrePass() &&
             !func->IsJitInDebugMode() &&
    -        (func->HasProfileInfo() && !func->GetReadOnlyProfileInfo()->IsMemOpDisabled()) &&
    +        !func->IsMemOpDisabled() &&
             this->currentBlock->loop->doMemOp)
         {
             CollectMemOpInfo(instrPrev, instr, src1Val, src2Val);
    @@ -16531,6 +16531,7 @@ GlobOpt::GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opn
             if (instr->HasBailOutInfo())
             {
                 instr->SetBailOutKind(instr->GetBailOutKind() | IR::BailOutMarkTempObject);
    +            instr->GetBailOutInfo()->canDeadStore = false;
             }
             else
             {
    @@ -16540,6 +16541,11 @@ GlobOpt::GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opn
                     || (instr->m_opcode == Js::OpCode::FromVar && !opnd->GetValueType().IsPrimitive())
                     || propertySymOpnd == nullptr
                     || !propertySymOpnd->IsTypeCheckProtected())
    +            {
    +                this->GenerateBailAtOperation(&instr, IR::BailOutMarkTempObject);
    +                instr->GetBailOutInfo()->canDeadStore = false;
    +            }
    +            else if (propertySymOpnd->MayHaveImplicitCall())
                 {
                     this->GenerateBailAtOperation(&instr, IR::BailOutMarkTempObject);
                 }
    @@ -16680,7 +16686,14 @@ GlobOpt::GenerateInductionVariableChangeForMemOp(Loop *loop, byte unroll, IR::In
         }
         else
         {
    -        uint size = (loopCount->LoopCountMinusOneConstantValue() + 1)  * unroll;
    +        int32 loopCountMinusOnePlusOne;
    +        int32 size;
    +        if (Int32Math::Add(loopCount->LoopCountMinusOneConstantValue(), 1, &loopCountMinusOnePlusOne) ||
    +            Int32Math::Mul(loopCountMinusOnePlusOne, unroll, &size))
    +        {
    +            throw Js::RejitException(RejitReason::MemOpDisabled);
    +        }
    +        Assert(size > 0);
             sizeOpnd = IR::IntConstOpnd::New(size, IRType::TyUint32, localFunc);
         }
         loop->memOpInfo->inductionVariableOpndPerUnrollMap->Add(unroll, sizeOpnd);
    
  • lib/Backend/GlobOptFields.cpp+8 0 modified
    @@ -410,6 +410,14 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
             if (inGlobOpt)
             {
                 KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
    +            if (this->objectTypeSyms)
    +            {
    +                if (this->currentBlock->globOptData.maybeWrittenTypeSyms == nullptr)
    +                {
    +                    this->currentBlock->globOptData.maybeWrittenTypeSyms = JitAnew(this->alloc, BVSparse<JitArenaAllocator>, this->alloc);
    +                }
    +                this->currentBlock->globOptData.maybeWrittenTypeSyms->Or(this->objectTypeSyms);
    +            }
             }
     
             // fall through
    
  • lib/Backend/JITOutput.cpp+6 0 modified
    @@ -65,6 +65,12 @@ JITOutput::IsTrackCompoundedIntOverflowDisabled() const
         return m_outputData->disableTrackCompoundedIntOverflow != FALSE;
     }
     
    +bool
    +JITOutput::IsMemOpDisabled() const
    +{
    +    return m_outputData->disableMemOp != FALSE;
    +}
    +
     bool
     JITOutput::IsArrayCheckHoistDisabled() const
     {
    
  • lib/Backend/JITOutput.h+1 0 modified
    @@ -22,6 +22,7 @@ class JITOutput
         void RecordXData(BYTE * xdata);
     #endif
         bool IsTrackCompoundedIntOverflowDisabled() const;
    +    bool IsMemOpDisabled() const;
         bool IsArrayCheckHoistDisabled() const;
         bool IsStackArgOptDisabled() const;
         bool IsSwitchOptDisabled() const;
    
  • lib/Backend/NativeCodeGenerator.cpp+4 0 modified
    @@ -1234,6 +1234,10 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
             {
                 body->GetAnyDynamicProfileInfo()->DisableTrackCompoundedIntOverflow();
             }
    +        if (jitWriteData.disableMemOp)
    +        {
    +            body->GetAnyDynamicProfileInfo()->DisableMemOp();
    +        }
         }
     
         if (jitWriteData.disableInlineApply)
    
  • lib/Backend/Opnd.cpp+5 6 modified
    @@ -962,7 +962,8 @@ PropertySymOpnd::IsObjectHeaderInlined() const
     bool
     PropertySymOpnd::ChangesObjectLayout() const
     {
    -    JITTypeHolder cachedType = this->IsMono() ? this->GetType() : this->GetFirstEquivalentType();
    +    JITTypeHolder cachedType = this->HasInitialType() ? this->GetInitialType() : 
    +        this->IsMono() ? this->GetType() : this->GetFirstEquivalentType();
     
         JITTypeHolder finalType = this->GetFinalType();
     
    @@ -987,13 +988,11 @@ PropertySymOpnd::ChangesObjectLayout() const
             // This is the case where the type transition actually occurs. (This is the only case that's detectable
             // during the loop pre-pass, since final types are not in place yet.)
     
    -        Assert(cachedType != nullptr && Js::DynamicType::Is(cachedType->GetTypeId()));
    -
    -        const JITTypeHandler * cachedTypeHandler = cachedType->GetTypeHandler();
             const JITTypeHandler * initialTypeHandler = initialType->GetTypeHandler();
     
    -        return cachedTypeHandler->GetInlineSlotCapacity() != initialTypeHandler->GetInlineSlotCapacity() ||
    -            cachedTypeHandler->GetOffsetOfInlineSlots() != initialTypeHandler->GetOffsetOfInlineSlots();
    +        // If no final type has been set in the forward pass, then we have no way of knowing how the object shape will evolve here.
    +        // If the initial type is object-header-inlined, assume that the layout may change.
    +        return initialTypeHandler->IsObjectHeaderInlinedTypeHandler();
         }
     
         return false;
    
  • lib/Backend/Opnd.h+2 1 modified
    @@ -1138,7 +1138,8 @@ class PropertySymOpnd sealed : public SymOpnd
         // fall back on live cache.  Similarly, for fixed method checks.
         bool MayHaveImplicitCall() const
         {
    -        return !IsRootObjectNonConfigurableFieldLoad() && !UsesFixedValue() && (!IsTypeCheckSeqCandidate() || !IsTypeCheckProtected());
    +        return !IsRootObjectNonConfigurableFieldLoad() && !UsesFixedValue() && (!IsTypeCheckSeqCandidate() || !IsTypeCheckProtected()
    +            || (IsLoadedFromProto() && NeedsWriteGuardTypeCheck()));
         }
     
         // Is the instruction involving this operand part of a type check sequence? This is different from IsObjTypeSpecOptimized
    
  • 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 10
    +#define CHAKRA_CORE_PATCH_VERSION 11
     #define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0.
     
     // -------------
    
  • lib/JITIDL/JITTypes.h+10 5 modified
    @@ -838,37 +838,42 @@ typedef struct JITOutputIDL
         boolean disableStackArgOpt;
         boolean disableSwitchOpt;
         boolean disableTrackCompoundedIntOverflow;
    -    boolean isInPrereservedRegion;
    +    boolean disableMemOp;
     
    +    boolean isInPrereservedRegion;
         boolean hasBailoutInstr;
    -
         boolean hasJittedStackClosure;
    +    IDL_PAD1(0)
     
         unsigned short pdataCount;
         unsigned short xdataSize;
     
         unsigned short argUsedForBranch;
    +    IDL_PAD2(1)
     
         int localVarSlotsOffset; // FunctionEntryPointInfo only
    +
         int localVarChangedOffset; // FunctionEntryPointInfo only
         unsigned int frameHeight;
     
    -
         unsigned int codeSize;
         unsigned int throwMapOffset;
    +
         unsigned int throwMapCount;
         unsigned int inlineeFrameOffsetArrayOffset;
    -    unsigned int inlineeFrameOffsetArrayCount;
     
    +    unsigned int inlineeFrameOffsetArrayCount;
         unsigned int propertyGuardCount;
    +
         unsigned int ctorCachesCount;
    +    X64_PAD4(2)
     
     #if TARGET_64
         CHAKRA_PTR xdataAddr;
     #elif defined(_M_ARM)
         unsigned int xdataOffset;
     #else
    -    X86_PAD4(0)
    +    X86_PAD4(3)
     #endif
         CHAKRA_PTR codeAddress;
         CHAKRA_PTR thunkAddress;
    
75162b7f2d8a

[MERGE #6196 @atulkatti] ChakraCore servicing update for July, 2019

https://github.com/chakra-core/ChakraCoreAtul KattiJul 9, 2019via ghsa
16 files changed · +81 27
  • Build/NuGet/.pack-version+1 1 modified
    @@ -1 +1 @@
    -1.11.10
    +1.11.11
    
  • lib/Backend/BackwardPass.cpp+8 4 modified
    @@ -4151,13 +4151,17 @@ BackwardPass::UpdateImplicitCallBailOutKind(IR::Instr *const instr, bool needsBa
     
         IR::BailOutKind implicitCallBailOutKind = needsBailOutOnImplicitCall ? IR::BailOutOnImplicitCalls : IR::BailOutInvalid;
     
    -    const IR::BailOutKind instrBailOutKind = instr->GetBailOutKind();
    +    IR::BailOutKind instrBailOutKind = instr->GetBailOutKind();
         if (instrBailOutKind & IR::BailOutMarkTempObject)
         {
    -        // Don't remove the implicit call pre op bailout for mark temp object
             // Remove the mark temp object bit, as we don't need it after the dead store pass
    -        instr->SetBailOutKind(instrBailOutKind & ~IR::BailOutMarkTempObject);
    -        return true;
    +        instrBailOutKind &= ~IR::BailOutMarkTempObject;
    +        instr->SetBailOutKind(instrBailOutKind);
    +
    +        if (!instr->GetBailOutInfo()->canDeadStore)
    +        {
    +            return true;
    +        }
         }
     
         const IR::BailOutKind instrImplicitCallBailOutKind = instrBailOutKind & ~IR::BailOutKindBits;
    
  • lib/Backend/BailOut.h+2 1 modified
    @@ -27,7 +27,7 @@ class BailOutInfo
         BailOutInfo(uint32 bailOutOffset, Func* bailOutFunc) :
             bailOutOffset(bailOutOffset), bailOutFunc(bailOutFunc),
             byteCodeUpwardExposedUsed(nullptr), polymorphicCacheIndex((uint)-1), startCallCount(0), startCallInfo(nullptr), bailOutInstr(nullptr),
    -        totalOutParamCount(0), argOutSyms(nullptr), bailOutRecord(nullptr), wasCloned(false), isInvertedBranch(false), sharedBailOutKind(true), isLoopTopBailOutInfo(false),
    +        totalOutParamCount(0), argOutSyms(nullptr), bailOutRecord(nullptr), wasCloned(false), isInvertedBranch(false), sharedBailOutKind(true), isLoopTopBailOutInfo(false), canDeadStore(true),
             outParamInlinedArgSlot(nullptr), liveVarSyms(nullptr), liveLosslessInt32Syms(nullptr), liveFloat64Syms(nullptr),
             branchConditionOpnd(nullptr),
             stackLiteralBailOutInfoCount(0), stackLiteralBailOutInfo(nullptr)
    @@ -69,6 +69,7 @@ class BailOutInfo
     #endif
         bool wasCloned;
         bool isInvertedBranch;
    +    bool canDeadStore;
         bool sharedBailOutKind;
         bool isLoopTopBailOutInfo;
     
    
  • lib/Backend/Func.cpp+9 0 modified
    @@ -345,6 +345,9 @@ Func::Codegen(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
                 case RejitReason::TrackIntOverflowDisabled:
                     outputData->disableTrackCompoundedIntOverflow = TRUE;
                     break;
    +            case RejitReason::MemOpDisabled:
    +                outputData->disableMemOp = TRUE;
    +                break;
                 default:
                     Assume(UNREACHED);
                 }
    @@ -1124,6 +1127,12 @@ Func::IsTrackCompoundedIntOverflowDisabled() const
         return (HasProfileInfo() && GetReadOnlyProfileInfo()->IsTrackCompoundedIntOverflowDisabled()) || m_output.IsTrackCompoundedIntOverflowDisabled();
     }
     
    +bool
    +Func::IsMemOpDisabled() const
    +{
    +    return (HasProfileInfo() && GetReadOnlyProfileInfo()->IsMemOpDisabled()) || m_output.IsMemOpDisabled();
    +}
    +
     bool
     Func::IsArrayCheckHoistDisabled() const
     {
    
  • lib/Backend/Func.h+1 0 modified
    @@ -995,6 +995,7 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
         void SetScopeObjSym(StackSym * sym);
         StackSym * GetScopeObjSym();
         bool IsTrackCompoundedIntOverflowDisabled() const;
    +    bool IsMemOpDisabled() const;
         bool IsArrayCheckHoistDisabled() const;
         bool IsStackArgOptDisabled() const;
         bool IsSwitchOptDisabled() const;
    
  • lib/Backend/GlobOptBlockData.cpp+7 5 modified
    @@ -974,7 +974,8 @@ GlobOptBlockData::MergeValueInfo(
                     fromDataValueInfo->AsArrayValueInfo(),
                     fromDataSym,
                     symsRequiringCompensation,
    -                symsCreatedForMerge);
    +                symsCreatedForMerge,
    +                isLoopBackEdge);
         }
     
         // Consider: If both values are VarConstantValueInfo with the same value, we could
    @@ -1072,7 +1073,8 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
         const ArrayValueInfo *const fromDataValueInfo,
         Sym *const arraySym,
         BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
    -    BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
    +    BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
    +    bool isLoopBackEdge)
     {
         Assert(mergedValueType.IsAnyOptimizedArray());
         Assert(toDataValueInfo);
    @@ -1095,7 +1097,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     // Adding compensation code in the prepass won't help, as the symstores would again be different in the main pass.
                     Assert(symsRequiringCompensation);
    @@ -1123,7 +1125,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     Assert(symsRequiringCompensation);
                     symsRequiringCompensation->Set(arraySym->m_id);
    @@ -1150,7 +1152,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     Assert(symsRequiringCompensation);
                     symsRequiringCompensation->Set(arraySym->m_id);
    
  • lib/Backend/GlobOptBlockData.h+1 1 modified
    @@ -264,7 +264,7 @@ class GlobOptBlockData
         Value *                 MergeValues(Value *toDataValue, Value *fromDataValue, Sym *fromDataSym, bool isLoopBackEdge, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
         ValueInfo *             MergeValueInfo(Value *toDataVal, Value *fromDataVal, Sym *fromDataSym, bool isLoopBackEdge, bool sameValueNumber, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
         JsTypeValueInfo *       MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber);
    -    ValueInfo *             MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
    +    ValueInfo *             MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge, bool isLoopBackEdge);
     
         // Argument Tracking
     public:
    
  • lib/Backend/GlobOpt.cpp+15 2 modified
    @@ -2624,7 +2624,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
             !(instr->IsJitProfilingInstr()) &&
             this->currentBlock->loop && !IsLoopPrePass() &&
             !func->IsJitInDebugMode() &&
    -        (func->HasProfileInfo() && !func->GetReadOnlyProfileInfo()->IsMemOpDisabled()) &&
    +        !func->IsMemOpDisabled() &&
             this->currentBlock->loop->doMemOp)
         {
             CollectMemOpInfo(instrPrev, instr, src1Val, src2Val);
    @@ -16531,6 +16531,7 @@ GlobOpt::GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opn
             if (instr->HasBailOutInfo())
             {
                 instr->SetBailOutKind(instr->GetBailOutKind() | IR::BailOutMarkTempObject);
    +            instr->GetBailOutInfo()->canDeadStore = false;
             }
             else
             {
    @@ -16540,6 +16541,11 @@ GlobOpt::GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opn
                     || (instr->m_opcode == Js::OpCode::FromVar && !opnd->GetValueType().IsPrimitive())
                     || propertySymOpnd == nullptr
                     || !propertySymOpnd->IsTypeCheckProtected())
    +            {
    +                this->GenerateBailAtOperation(&instr, IR::BailOutMarkTempObject);
    +                instr->GetBailOutInfo()->canDeadStore = false;
    +            }
    +            else if (propertySymOpnd->MayHaveImplicitCall())
                 {
                     this->GenerateBailAtOperation(&instr, IR::BailOutMarkTempObject);
                 }
    @@ -16680,7 +16686,14 @@ GlobOpt::GenerateInductionVariableChangeForMemOp(Loop *loop, byte unroll, IR::In
         }
         else
         {
    -        uint size = (loopCount->LoopCountMinusOneConstantValue() + 1)  * unroll;
    +        int32 loopCountMinusOnePlusOne;
    +        int32 size;
    +        if (Int32Math::Add(loopCount->LoopCountMinusOneConstantValue(), 1, &loopCountMinusOnePlusOne) ||
    +            Int32Math::Mul(loopCountMinusOnePlusOne, unroll, &size))
    +        {
    +            throw Js::RejitException(RejitReason::MemOpDisabled);
    +        }
    +        Assert(size > 0);
             sizeOpnd = IR::IntConstOpnd::New(size, IRType::TyUint32, localFunc);
         }
         loop->memOpInfo->inductionVariableOpndPerUnrollMap->Add(unroll, sizeOpnd);
    
  • lib/Backend/GlobOptFields.cpp+8 0 modified
    @@ -410,6 +410,14 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
             if (inGlobOpt)
             {
                 KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
    +            if (this->objectTypeSyms)
    +            {
    +                if (this->currentBlock->globOptData.maybeWrittenTypeSyms == nullptr)
    +                {
    +                    this->currentBlock->globOptData.maybeWrittenTypeSyms = JitAnew(this->alloc, BVSparse<JitArenaAllocator>, this->alloc);
    +                }
    +                this->currentBlock->globOptData.maybeWrittenTypeSyms->Or(this->objectTypeSyms);
    +            }
             }
     
             // fall through
    
  • lib/Backend/JITOutput.cpp+6 0 modified
    @@ -65,6 +65,12 @@ JITOutput::IsTrackCompoundedIntOverflowDisabled() const
         return m_outputData->disableTrackCompoundedIntOverflow != FALSE;
     }
     
    +bool
    +JITOutput::IsMemOpDisabled() const
    +{
    +    return m_outputData->disableMemOp != FALSE;
    +}
    +
     bool
     JITOutput::IsArrayCheckHoistDisabled() const
     {
    
  • lib/Backend/JITOutput.h+1 0 modified
    @@ -22,6 +22,7 @@ class JITOutput
         void RecordXData(BYTE * xdata);
     #endif
         bool IsTrackCompoundedIntOverflowDisabled() const;
    +    bool IsMemOpDisabled() const;
         bool IsArrayCheckHoistDisabled() const;
         bool IsStackArgOptDisabled() const;
         bool IsSwitchOptDisabled() const;
    
  • lib/Backend/NativeCodeGenerator.cpp+4 0 modified
    @@ -1234,6 +1234,10 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
             {
                 body->GetAnyDynamicProfileInfo()->DisableTrackCompoundedIntOverflow();
             }
    +        if (jitWriteData.disableMemOp)
    +        {
    +            body->GetAnyDynamicProfileInfo()->DisableMemOp();
    +        }
         }
     
         if (jitWriteData.disableInlineApply)
    
  • lib/Backend/Opnd.cpp+5 6 modified
    @@ -962,7 +962,8 @@ PropertySymOpnd::IsObjectHeaderInlined() const
     bool
     PropertySymOpnd::ChangesObjectLayout() const
     {
    -    JITTypeHolder cachedType = this->IsMono() ? this->GetType() : this->GetFirstEquivalentType();
    +    JITTypeHolder cachedType = this->HasInitialType() ? this->GetInitialType() : 
    +        this->IsMono() ? this->GetType() : this->GetFirstEquivalentType();
     
         JITTypeHolder finalType = this->GetFinalType();
     
    @@ -987,13 +988,11 @@ PropertySymOpnd::ChangesObjectLayout() const
             // This is the case where the type transition actually occurs. (This is the only case that's detectable
             // during the loop pre-pass, since final types are not in place yet.)
     
    -        Assert(cachedType != nullptr && Js::DynamicType::Is(cachedType->GetTypeId()));
    -
    -        const JITTypeHandler * cachedTypeHandler = cachedType->GetTypeHandler();
             const JITTypeHandler * initialTypeHandler = initialType->GetTypeHandler();
     
    -        return cachedTypeHandler->GetInlineSlotCapacity() != initialTypeHandler->GetInlineSlotCapacity() ||
    -            cachedTypeHandler->GetOffsetOfInlineSlots() != initialTypeHandler->GetOffsetOfInlineSlots();
    +        // If no final type has been set in the forward pass, then we have no way of knowing how the object shape will evolve here.
    +        // If the initial type is object-header-inlined, assume that the layout may change.
    +        return initialTypeHandler->IsObjectHeaderInlinedTypeHandler();
         }
     
         return false;
    
  • lib/Backend/Opnd.h+2 1 modified
    @@ -1138,7 +1138,8 @@ class PropertySymOpnd sealed : public SymOpnd
         // fall back on live cache.  Similarly, for fixed method checks.
         bool MayHaveImplicitCall() const
         {
    -        return !IsRootObjectNonConfigurableFieldLoad() && !UsesFixedValue() && (!IsTypeCheckSeqCandidate() || !IsTypeCheckProtected());
    +        return !IsRootObjectNonConfigurableFieldLoad() && !UsesFixedValue() && (!IsTypeCheckSeqCandidate() || !IsTypeCheckProtected()
    +            || (IsLoadedFromProto() && NeedsWriteGuardTypeCheck()));
         }
     
         // Is the instruction involving this operand part of a type check sequence? This is different from IsObjTypeSpecOptimized
    
  • 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 10
    +#define CHAKRA_CORE_PATCH_VERSION 11
     #define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0.
     
     // -------------
    
  • lib/JITIDL/JITTypes.h+10 5 modified
    @@ -838,37 +838,42 @@ typedef struct JITOutputIDL
         boolean disableStackArgOpt;
         boolean disableSwitchOpt;
         boolean disableTrackCompoundedIntOverflow;
    -    boolean isInPrereservedRegion;
    +    boolean disableMemOp;
     
    +    boolean isInPrereservedRegion;
         boolean hasBailoutInstr;
    -
         boolean hasJittedStackClosure;
    +    IDL_PAD1(0)
     
         unsigned short pdataCount;
         unsigned short xdataSize;
     
         unsigned short argUsedForBranch;
    +    IDL_PAD2(1)
     
         int localVarSlotsOffset; // FunctionEntryPointInfo only
    +
         int localVarChangedOffset; // FunctionEntryPointInfo only
         unsigned int frameHeight;
     
    -
         unsigned int codeSize;
         unsigned int throwMapOffset;
    +
         unsigned int throwMapCount;
         unsigned int inlineeFrameOffsetArrayOffset;
    -    unsigned int inlineeFrameOffsetArrayCount;
     
    +    unsigned int inlineeFrameOffsetArrayCount;
         unsigned int propertyGuardCount;
    +
         unsigned int ctorCachesCount;
    +    X64_PAD4(2)
     
     #if TARGET_64
         CHAKRA_PTR xdataAddr;
     #elif defined(_M_ARM)
         unsigned int xdataOffset;
     #else
    -    X86_PAD4(0)
    +    X86_PAD4(3)
     #endif
         CHAKRA_PTR codeAddress;
         CHAKRA_PTR thunkAddress;
    
d4e767fb9461

[CVE-2019-1092] Chakra JIT OOB R/W

https://github.com/chakra-core/ChakraCoreMichael HolmanJun 4, 2019via ghsa
2 files changed · +8 6
  • lib/Backend/GlobOptBlockData.cpp+7 5 modified
    @@ -974,7 +974,8 @@ GlobOptBlockData::MergeValueInfo(
                     fromDataValueInfo->AsArrayValueInfo(),
                     fromDataSym,
                     symsRequiringCompensation,
    -                symsCreatedForMerge);
    +                symsCreatedForMerge,
    +                isLoopBackEdge);
         }
     
         // Consider: If both values are VarConstantValueInfo with the same value, we could
    @@ -1072,7 +1073,8 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
         const ArrayValueInfo *const fromDataValueInfo,
         Sym *const arraySym,
         BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
    -    BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
    +    BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
    +    bool isLoopBackEdge)
     {
         Assert(mergedValueType.IsAnyOptimizedArray());
         Assert(toDataValueInfo);
    @@ -1095,7 +1097,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     // Adding compensation code in the prepass won't help, as the symstores would again be different in the main pass.
                     Assert(symsRequiringCompensation);
    @@ -1123,7 +1125,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     Assert(symsRequiringCompensation);
                     symsRequiringCompensation->Set(arraySym->m_id);
    @@ -1150,7 +1152,7 @@ ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
             }
             else
             {
    -            if (!this->globOpt->IsLoopPrePass())
    +            if (!this->globOpt->IsLoopPrePass() && !isLoopBackEdge)
                 {
                     Assert(symsRequiringCompensation);
                     symsRequiringCompensation->Set(arraySym->m_id);
    
  • lib/Backend/GlobOptBlockData.h+1 1 modified
    @@ -264,7 +264,7 @@ class GlobOptBlockData
         Value *                 MergeValues(Value *toDataValue, Value *fromDataValue, Sym *fromDataSym, bool isLoopBackEdge, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
         ValueInfo *             MergeValueInfo(Value *toDataVal, Value *fromDataVal, Sym *fromDataSym, bool isLoopBackEdge, bool sameValueNumber, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
         JsTypeValueInfo *       MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber);
    -    ValueInfo *             MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge);
    +    ValueInfo *             MergeArrayValueInfo(const ValueType mergedValueType, const ArrayValueInfo *const toDataValueInfo, const ArrayValueInfo *const fromDataValueInfo, Sym *const arraySym, BVSparse<JitArenaAllocator> *const symsRequiringCompensation, BVSparse<JitArenaAllocator> *const symsCreatedForMerge, bool isLoopBackEdge);
     
         // Argument Tracking
     public:
    

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.