VYPR
High severityNVD Advisory· Published Aug 15, 2018· Updated Aug 5, 2024

CVE-2018-8372

CVE-2018-8372

Description

A remote code execution vulnerability in the scripting engine of Microsoft browsers (ChakraCore, IE 11, Edge) due to a type confusion, allowing arbitrary code execution via a crafted webpage.

AI Insight

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

A remote code execution vulnerability in the scripting engine of Microsoft browsers (ChakraCore, IE 11, Edge) due to a type confusion, allowing arbitrary code execution via a crafted webpage.

Vulnerability

A type confusion vulnerability exists in the way the Chakra scripting engine handles objects in memory, affecting ChakraCore, Internet Explorer 11, and Microsoft Edge on all supported Windows platforms [1][3]. The flaw occurs in the Lowerer::GenerateProfiledNewScObjArrayFastPath and related functions where a memory corruption can be triggered [2]. This CVE is distinct from similar scripting engine vulnerabilities (CVE-2018-8353, etc.). Vulnerable versions include all releases before the August 2018 security updates.

Exploitation

An attacker can host a specially crafted website or inject malicious content into a site that the user visits. No special privileges are required; the user only needs to view the page with a vulnerable browser. The scripting engine's mishandling of object types leads to memory corruption, which the attacker can leverage to gain code execution.

Impact

Successful exploitation allows an attacker to execute arbitrary code in the context of the current user. If the user has administrative rights, the attacker can take full control of the system, install programs, view/change data, or create new accounts. The attack is remote and requires user interaction only to visit the malicious page.

Mitigation

Microsoft released security updates on August 14, 2018, to address this vulnerability [1][4]. Users should apply the latest updates via Windows Update. The fix is also available in ChakraCore commit 91bb6d6 [2]. No workarounds are listed; updating is the recommended mitigation.

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

Affected products

4

Patches

1
91bb6d68bfe0

[CVE-2018-8372] Edge - Report a type confusion bug in Edge - 360Vulcan

https://github.com/chakra-core/ChakraCoreRajat DuaJul 23, 2018via ghsa
23 files changed · +280 38
  • lib/Backend/amd64/LowererMDArch.cpp+19 0 modified
    @@ -3448,3 +3448,22 @@ LowererMDArch::LowerEHRegionReturn(IR::Instr * insertBeforeInstr, IR::Opnd * tar
         // return the last instruction inserted
         return retInstr;
     }
    +
    +IR::BranchInstr*
    +LowererMDArch::InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr)
    +{
    +    Assert(compareSrc->IsFloat64() && missingItemOpnd->IsUint64());
    +
    +    IR::Opnd * compareSrcUint64Opnd = IR::RegOpnd::New(TyUint64, m_func);
    +
    +    if (compareSrc->IsRegOpnd())
    +    {
    +        this->lowererMD->EmitReinterpretPrimitive(compareSrcUint64Opnd, compareSrc, insertBeforeInstr);
    +    }
    +    else if (compareSrc->IsIndirOpnd())
    +    {
    +        compareSrcUint64Opnd = compareSrc->UseWithNewType(TyUint64, m_func);
    +    }
    +
    +    return this->lowererMD->m_lowerer->InsertCompareBranch(missingItemOpnd, compareSrcUint64Opnd, opcode, target, insertBeforeInstr);
    +}
    \ No newline at end of file
    
  • lib/Backend/amd64/LowererMDArch.h+1 1 modified
    @@ -151,7 +151,7 @@ class LowererMDArch
     
         void                LowerInlineSpreadArgOutLoop(IR::Instr *callInstr, IR::RegOpnd *indexOpnd, IR::RegOpnd *arrayElementsStartOpnd);
         IR::Instr *         LowerEHRegionReturn(IR::Instr * insertBeforeInstr, IR::Opnd * targetOpnd);
    -
    +    IR::BranchInstr*    InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr);
     private:
         void                MovArgFromReg2Stack(IR::Instr * instr, RegNum reg, Js::ArgSlot slotNumber, IRType type = TyMachReg);
         void                GenerateStackAllocation(IR::Instr *instr, uint32 size);
    
  • lib/Backend/arm64/LowerMD.cpp+19 0 modified
    @@ -7051,6 +7051,25 @@ LowererMD::InsertObjectPoison(IR::Opnd* poisonedOpnd, IR::BranchInstr* branchIns
         }
     }
     
    +IR::BranchInstr*
    +LowererMD::InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr)
    +{
    +    Assert(compareSrc->IsFloat64() && missingItemOpnd->IsUint64());
    +
    +    IR::Opnd * compareSrcUint64Opnd = IR::RegOpnd::New(TyUint64, m_func);
    +    if (compareSrc->IsRegOpnd())
    +    {
    +        IR::Instr * movDoubleToUint64Instr = IR::Instr::New(Js::OpCode::FMOV_GEN, compareSrcUint64Opnd, compareSrc, insertBeforeInstr->m_func);
    +        insertBeforeInstr->InsertBefore(movDoubleToUint64Instr);
    +    }
    +    else if (compareSrc->IsIndirOpnd())
    +    {
    +        compareSrcUint64Opnd = compareSrc->UseWithNewType(TyUint64, m_func);
    +    }
    +
    +    return m_lowerer->InsertCompareBranch(compareSrcUint64Opnd, missingItemOpnd, opcode, target, insertBeforeInstr);
    +}
    +
     #if DBG
     //
     // Helps in debugging of fast paths.
    
  • lib/Backend/arm64/LowerMD.h+1 0 modified
    @@ -251,6 +251,7 @@ class LowererMD
                 void                GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed = false);
     
                 static void            InsertObjectPoison(IR::Opnd* poisonedOpnd, IR::BranchInstr* branchInstr, IR::Instr* insertInstr, bool isForStore);
    +            IR::BranchInstr*    InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr);
     
     private:
         static  IR::Instr *     ChangeToAssign(IR::Instr * instr, IRType destType);
    
  • lib/Backend/arm/ARMEncode.h+14 0 modified
    @@ -1203,6 +1203,20 @@ static const FormTable Forms_VMOVARMVFP[] =
         FT (NOMORE,   0x0,   0),
     };
     
    +static const FormTable Forms_VMOVF64R32L[] =
    +{
    +    FT(2dr______, 0x0b10ee00, Steps_FLT_FMSR_d0r),
    +    FT(2rd______, 0x0b10ee10, Steps_FLT_FMRS_rd0),
    +    FT(NOMORE,   0x0,   0),
    +};
    +
    +static const FormTable Forms_VMOVF64R32U[] =
    +{
    +    FT(2dr______, 0x0b10ee20, Steps_FLT_FMSR_d1r),
    +    FT(2rd______, 0x0b10ee30, Steps_FLT_FMRS_rd1),
    +    FT(NOMORE,   0x0,   0),
    +};
    +
     static const FormTable Forms_VCVTF64F32 [] =
     {
         FT (2dd______, 0x0ac0eeb7, Steps_FCVTDS_ds),
    
  • lib/Backend/arm/AssemblyStep.h+28 0 modified
    @@ -789,13 +789,41 @@ static const AssemblyStep Steps_FLT_FMSR_sr [] =
         STEP_OPCODE, STEP_DONE
     };
     
    +static const AssemblyStep Steps_FLT_FMSR_d0r[] =
    +{
    +    STEP_DREG, 0, 23, STEP_NEXTOPN,
    +    STEP_REG, 28,
    +    STEP_OPCODE, STEP_DONE
    +};
    +
    +static const AssemblyStep Steps_FLT_FMSR_d1r[] =
    +{
    +    STEP_DREG, 0, 23, STEP_NEXTOPN,
    +    STEP_REG, 28,
    +    STEP_OPCODE, STEP_DONE
    +};
    +
     static const AssemblyStep Steps_FLT_FMRS_rs [] =
     {
         STEP_REG, 28, STEP_NEXTOPN,
         STEP_SREG, 0, 23,
         STEP_OPCODE, STEP_DONE
     };
     
    +static const AssemblyStep Steps_FLT_FMRS_rd0[] =
    +{
    +    STEP_REG, 28, STEP_NEXTOPN,
    +    STEP_DREG, 0, 23,
    +    STEP_OPCODE, STEP_DONE
    +};
    +
    +static const AssemblyStep Steps_FLT_FMRS_rd1[] =
    +{
    +    STEP_REG, 28, STEP_NEXTOPN,
    +    STEP_DREG, 0, 23,
    +    STEP_OPCODE, STEP_DONE
    +};
    +
     static const AssemblyStep Steps_T2_PLD_offset [] =
     {
        STEP_BASED, STEP_BASEREG, 0,
    
  • lib/Backend/arm/EncoderMD.cpp+2 0 modified
    @@ -194,6 +194,8 @@ InstructionType EncoderMD::CanonicalizeInstr(IR::Instr* instr)
             case Js::OpCode::VSQRT:
             case Js::OpCode::VMOV:
             case Js::OpCode::VMOVARMVFP:
    +        case Js::OpCode::VMOVF64R32L:
    +        case Js::OpCode::VMOVF64R32U:
             case Js::OpCode::VCVTF64F32:
             case Js::OpCode::VCVTF32F64:
             case Js::OpCode::VCVTF64S32:
    
  • lib/Backend/arm/LowerMD.cpp+24 0 modified
    @@ -7695,6 +7695,30 @@ LowererMD::LowerTypeof(IR::Instr* typeOfInstr)
         m_lowerer->LowerUnaryHelperMem(typeOfInstr, IR::HelperOp_Typeof);
     }
     
    +IR::BranchInstr*
    +LowererMD::InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr)
    +{
    +    Assert(compareSrc->IsFloat64() && missingItemOpnd->IsUInt32());
    +
    +    IR::Opnd * compareSrcUint32Opnd = IR::RegOpnd::New(TyUint32, m_func);
    +    IR::RegOpnd* tmpDoubleRegOpnd = IR::RegOpnd::New(TyFloat64, m_func);
    +
    +    if (compareSrc->IsIndirOpnd())
    +    {
    +        Lowerer::InsertMove(tmpDoubleRegOpnd, compareSrc, insertBeforeInstr);
    +    }
    +    else
    +    {
    +        tmpDoubleRegOpnd = compareSrc->AsRegOpnd();
    +    }
    +
    +    IR::Instr * movInstr = IR::Instr::New(Js::OpCode::VMOVF64R32U, compareSrcUint32Opnd, tmpDoubleRegOpnd, m_func);
    +    insertBeforeInstr->InsertBefore(movInstr);
    +    Legalize(movInstr);
    +
    +    return m_lowerer->InsertCompareBranch(missingItemOpnd, compareSrcUint32Opnd, opcode, target, insertBeforeInstr);
    +}
    +
     #if DBG
     //
     // Helps in debugging of fast paths.
    
  • lib/Backend/arm/LowerMD.h+1 0 modified
    @@ -247,6 +247,7 @@ class LowererMD
                 void                LowerInlineSpreadArgOutLoop(IR::Instr *callInstr, IR::RegOpnd *indexOpnd, IR::RegOpnd *arrayElementsStartOpnd);
                 void                LowerTypeof(IR::Instr * typeOfInstr);
                 void                GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed = false);
    +            IR::BranchInstr*    InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr);
     private:
         IR::Opnd* IsOpndNegZero(IR::Opnd* opnd, IR::Instr* instr);
     
    
  • lib/Backend/arm/MdOpCodes.h+2 0 modified
    @@ -159,6 +159,8 @@ MACRO(VLDR,     Reg2,      0,              0,  LEGAL_VLOAD,     INSTR_TYPE(Forms
     MACRO(VLDR32,   Reg2,      0,              0,  LEGAL_VLOAD,     INSTR_TYPE(Forms_VLDR32), DL__C) //single precision float load
     MACRO(VMOV,     Reg2,      0,              0,  LEGAL_REG2,      INSTR_TYPE(Forms_VMOV),   DM__C)
     MACRO(VMOVARMVFP, Reg2,    0,              0,  LEGAL_REG2,      INSTR_TYPE(Forms_VMOVARMVFP),   DM__C)
    +MACRO(VMOVF64R32L, Reg2,   0,              0,  LEGAL_REG2,      INSTR_TYPE(Forms_VMOVF64R32L), DM__C) // transfer bits between integral register and lower 4 bytes of double register
    +MACRO(VMOVF64R32U, Reg2,   0,              0,  LEGAL_REG2,      INSTR_TYPE(Forms_VMOVF64R32U), DM__C) // transfer bits between integral register and upper 4 bytes of double register
     MACRO(VMRS,     Empty,     OpSideEffect,   0,  LEGAL_NONE,      INSTR_TYPE(Forms_VMRS),   D___C)
     MACRO(VMRSR,    Reg1,      OpSideEffect,   0,  LEGAL_NONE,      INSTR_TYPE(Forms_VMRSR),   D___C)
     MACRO(VMSR,     Reg1,      OpSideEffect,   0,  LEGAL_NONE,      INSTR_TYPE(Forms_VMSR),   D___C)
    
  • lib/Backend/BackwardPass.cpp+2 2 modified
    @@ -4907,8 +4907,8 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
         }
     
         IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
    -    if(!baseValueType.IsNotNativeArray() &&
    -        (!baseValueType.IsLikelyNativeArray() || !instr->GetSrc1()->IsInt32()) &&
    +    if (!baseValueType.IsNotNativeArray() &&
    +        (!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
             !currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
             !(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
         {
    
  • lib/Backend/i386/LowererMDArch.cpp+47 0 modified
    @@ -4178,3 +4178,50 @@ LowererMDArch::LowerEHRegionReturn(IR::Instr * insertBeforeInstr, IR::Opnd * tar
         // return the last instruction inserted
         return retInstr;
     }
    +
    +IR::BranchInstr*
    +LowererMDArch::InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr)
    +{
    +    Assert(compareSrc->IsFloat64() && missingItemOpnd->IsUInt32());
    +
    +    IR::Opnd * compareSrcUint32Opnd = IR::RegOpnd::New(TyUint32, m_func);
    +
    +    // Missing item NaN have a different bit pattern from k_Nan, but is a NaN nonetheless. Given that, it is sufficient
    +    // to compare just the top 32 bits
    +    //
    +    // IF sse4.1 available
    +    // mov xmm0, compareSrc
    +    // pextrd ecx, xmm0, 1       <-- ecx will containg xmm0[63:32] after this
    +    // cmp missingItemOpnd, ecx
    +    // jcc target 
    +    //
    +    // ELSE
    +    // mov xmm0, compareSrc
    +    // shufps xmm0, xmm0, (3 << 6 | 2 << 4 | 1 << 2 | 1) <-- xmm0[31:0] will contain compareSrc[63:32] after this
    +    // movd ecx, xmm0
    +    // cmp missingItemOpnd, ecx
    +    // jcc $target
    +
    +    IR::RegOpnd* tmpDoubleRegOpnd = IR::RegOpnd::New(TyFloat64, m_func);
    +
    +    if (AutoSystemInfo::Data.SSE4_1Available())
    +    {
    +        if (compareSrc->IsIndirOpnd())
    +        {
    +            Lowerer::InsertMove(tmpDoubleRegOpnd, compareSrc, insertBeforeInstr);
    +        }
    +        else
    +        {
    +            tmpDoubleRegOpnd = compareSrc->AsRegOpnd();
    +        }
    +        Lowerer::InsertAndLegalize(IR::Instr::New(Js::OpCode::PEXTRD, compareSrcUint32Opnd, tmpDoubleRegOpnd, IR::IntConstOpnd::New(1, TyInt8, m_func, true), m_func), insertBeforeInstr);
    +    }
    +    else
    +    {
    +        Lowerer::InsertMove(tmpDoubleRegOpnd, compareSrc, insertBeforeInstr);
    +        Lowerer::InsertAndLegalize(IR::Instr::New(Js::OpCode::SHUFPS, tmpDoubleRegOpnd, tmpDoubleRegOpnd, IR::IntConstOpnd::New(3 << 6 | 2 << 4 | 1 << 2 | 1, TyInt8, m_func, true), m_func), insertBeforeInstr);
    +        Lowerer::InsertAndLegalize(IR::Instr::New(Js::OpCode::MOVD, compareSrcUint32Opnd, tmpDoubleRegOpnd, m_func), insertBeforeInstr);
    +    }
    +
    +    return this->lowererMD->m_lowerer->InsertCompareBranch(missingItemOpnd, compareSrcUint32Opnd, opcode, target, insertBeforeInstr);
    +}
    \ No newline at end of file
    
  • lib/Backend/i386/LowererMDArch.h+1 1 modified
    @@ -121,7 +121,7 @@ class LowererMDArch
     
                 void                LowerInlineSpreadArgOutLoop(IR::Instr *callInstr, IR::RegOpnd *indexOpnd, IR::RegOpnd *arrayElementsStartOpnd);
                 IR::Instr *         LowerEHRegionReturn(IR::Instr * insertBeforeInstr, IR::Opnd * targetOpnd);
    -
    +            IR::BranchInstr*    InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr);
     private:
                 void                GeneratePreCall(IR::Instr * callInstr, IR::Opnd  *functionObjOpnd);
     };
    
  • lib/Backend/Lower.cpp+79 24 modified
    @@ -4207,7 +4207,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi
             {
                 // Ensure we don't write missingItems past allocation size
                 Assert(offsetStart + missingItemIndex * sizeOfElement <= maxAllocationSize);
    -            GenerateMemInit(headOpnd, offsetStart + missingItemIndex * sizeOfElement, GetMissingItemOpnd(missingItemType, func), instr, true /*isZeroed*/);
    +            GenerateMemInit(headOpnd, offsetStart + missingItemIndex * sizeOfElement, GetMissingItemOpndForAssignment(missingItemType, func), instr, true /*isZeroed*/);
                 missingItemIndex++;
             }
     
    @@ -10802,7 +10802,7 @@ Lowerer::LowerStElemC(IR::Instr * stElem)
                 IR::Opnd* missingElementOpnd = GetMissingItemOpnd(stElem->GetSrc1()->GetType(), m_func);
                 if (!stElem->GetSrc1()->IsEqual(missingElementOpnd))
                 {
    -                InsertCompareBranch(stElem->GetSrc1(), missingElementOpnd , Js::OpCode::BrEq_A, labelBailOut, stElem, true);
    +                InsertMissingItemCompareBranch(stElem->GetSrc1(), Js::OpCode::BrEq_A, labelBailOut, stElem);
                 }
                 else
                 {
    @@ -11858,7 +11858,7 @@ Lowerer::GenerateHelperToArrayPopFastPath(IR::Instr * instr, IR::LabelInstr * do
             if(retInstr->GetDst())
             {
                 //Do this check only for native arrays with Dst. For Var arrays, this is taken care in the Runtime helper itself.
    -            InsertCompareBranch(GetMissingItemOpnd(retInstr->GetDst()->GetType(), m_func), retInstr->GetDst(), Js::OpCode::BrNeq_A, doneLabel, bailOutLabelHelper);
    +            InsertMissingItemCompareBranch(retInstr->GetDst(), Js::OpCode::BrNeq_A, doneLabel, bailOutLabelHelper);
             }
             else
             {
    @@ -16459,13 +16459,11 @@ Lowerer::GenerateFastElemIIntIndexCommon(
                 Assert(instr->m_opcode != Js::OpCode::InlineArrayPush || bailOutLabelInstr);
     
                 // Check for a write of the MissingItem value.
    -            InsertCompareBranch(
    +            InsertMissingItemCompareBranch(
                     element,
    -                GetMissingItemOpnd(elementType, m_func),
                     Js::OpCode::BrEq_A,
                     instr->m_opcode == Js::OpCode::InlineArrayPush ? bailOutLabelInstr : labelCantUseArray,
    -                instr,
    -                true);
    +                instr);
             }
     
             if(!headSegmentOpnd)
    @@ -16985,17 +16983,15 @@ Lowerer::GenerateFastElemIIntIndexCommon(
                     //If the array has missing values, check for one
                     if (!baseValueType.HasNoMissingValues())
                     {
    -                    InsertCompareBranch(
    +                    InsertMissingItemCompareBranch(
                             dst,
    -                        GetMissingItemOpnd(indirType, m_func),
                             Js::OpCode::BrEq_A,
                             bailOutLabelInstr,
    -                        instr,
    -                        true);
    +                        instr);
                     }
                 }
                 //  MOV [head + offset], missing
    -            InsertMove(indirOpnd, GetMissingItemOpnd(indirType, m_func), instr);
    +            InsertMove(indirOpnd, GetMissingItemOpndForAssignment(indirType, m_func), instr);
     
                 IR::Opnd *newLengthOpnd;
                 IR::AutoReuseOpnd autoReuseNewLengthOpnd;
    @@ -17276,6 +17272,22 @@ Lowerer::GenerateFastElemIIntIndexCommon(
         return indirOpnd;
     }
     
    +IR::BranchInstr*
    +Lowerer::InsertMissingItemCompareBranch(IR::Opnd* compareSrc, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr)
    +{
    +    IR::Opnd* missingItemOpnd = GetMissingItemOpndForCompare(compareSrc->GetType(), m_func);
    +    if (compareSrc->IsFloat64())
    +    {
    +        Assert(compareSrc->IsRegOpnd() || compareSrc->IsIndirOpnd());
    +        return m_lowererMD.InsertMissingItemCompareBranch(compareSrc, missingItemOpnd, opcode, target, insertBeforeInstr);
    +    }
    +    else
    +    {
    +        Assert(compareSrc->IsInt32() || compareSrc->IsVar());
    +        return InsertCompareBranch(missingItemOpnd, compareSrc, opcode, target, insertBeforeInstr, true);
    +    }
    +}
    +
     IR::RegOpnd *
     Lowerer::GenerateUntagVar(IR::RegOpnd * opnd, IR::LabelInstr * labelFail, IR::Instr * insertBeforeInstr, bool generateTagCheck)
     {
    @@ -17836,13 +17848,11 @@ Lowerer::GenerateFastLdElemI(IR::Instr *& ldElem, bool *instrIsInHelperBlockRef)
                 {
                     //  TEST dst, dst
                     //  JEQ $helper | JNE $fallthrough
    -                InsertCompareBranch(
    +                InsertMissingItemCompareBranch(
                         dst,
    -                    GetMissingItemOpnd(dst->GetType(), m_func),
                         needObjectTest ? Js::OpCode::BrEq_A : Js::OpCode::BrNeq_A,
                         needObjectTest ? labelHelper : labelFallThru,
    -                    ldElem,
    -                    true);
    +                    ldElem);
     
                     if (isNativeArrayLoad)
                     {
    @@ -17928,7 +17938,7 @@ Lowerer::GenerateFastLdElemI(IR::Instr *& ldElem, bool *instrIsInHelperBlockRef)
                         labelMissingNative = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
                     }
     
    -                InsertCompareBranch(GetMissingItemOpnd(ldElem->GetDst()->GetType(), m_func), ldElem->GetDst(), Js::OpCode::BrEq_A, labelMissingNative, insertBeforeInstr, true);
    +                InsertMissingItemCompareBranch(ldElem->GetDst(), Js::OpCode::BrEq_A, labelMissingNative, insertBeforeInstr);
                 }
                 InsertBranch(Js::OpCode::Br, labelFallThru, insertBeforeInstr);
                 if(labelMissingNative)
    @@ -17960,7 +17970,7 @@ Lowerer::GenerateFastLdElemI(IR::Instr *& ldElem, bool *instrIsInHelperBlockRef)
             {
                 if(!emitBailout)
                 {
    -                InsertCompareBranch(GetMissingItemOpnd(ldElem->GetDst()->GetType(), m_func), ldElem->GetDst(), Js::OpCode::BrEq_A, labelBailOut, insertBeforeInstr, true);
    +                InsertMissingItemCompareBranch(ldElem->GetDst(), Js::OpCode::BrEq_A, labelBailOut, insertBeforeInstr);
                 }
     
                 InsertBranch(Js::OpCode::Br, labelFallThru, insertBeforeInstr);
    @@ -17990,8 +18000,48 @@ Lowerer::GetMissingItemOpnd(IRType type, Func *func)
         {
             return IR::IntConstOpnd::New(Js::JavascriptNativeIntArray::MissingItem, TyInt32, func, true);
         }
    -    Assert(type == TyFloat64);
    -    return IR::MemRefOpnd::New(func->GetThreadContextInfo()->GetNativeFloatArrayMissingItemAddr(), TyFloat64, func);
    +    AssertMsg(false, "Only expecting TyVar and TyInt32 in Lowerer::GetMissingItemOpnd");
    +    __assume(false);
    +}
    +
    +IR::Opnd*
    +Lowerer::GetMissingItemOpndForAssignment(IRType type, Func *func)
    +{
    +    switch (type)
    +    {
    +    case TyVar:
    +    case TyInt32:
    +        return GetMissingItemOpnd(type, func);
    +
    +    case TyFloat64:
    +        return IR::MemRefOpnd::New(func->GetThreadContextInfo()->GetNativeFloatArrayMissingItemAddr(), TyFloat64, func);
    +
    +    default:
    +        AnalysisAssertMsg(false, "Unexpected type in Lowerer::GetMissingItemOpndForAssignment");
    +        __assume(false);
    +    }
    +}
    +
    +IR::Opnd *
    +Lowerer::GetMissingItemOpndForCompare(IRType type, Func *func)
    +{
    +    switch (type)
    +    {
    +    case TyVar:
    +    case TyInt32:
    +        return GetMissingItemOpnd(type, func);
    +
    +    case TyFloat64:
    +#if TARGET_64
    +        return IR::MemRefOpnd::New(func->GetThreadContextInfo()->GetNativeFloatArrayMissingItemAddr(), TyUint64, func);
    +#else
    +        return IR::MemRefOpnd::New(func->GetThreadContextInfo()->GetNativeFloatArrayMissingItemAddr(), TyUint32, func);
    +#endif
    +
    +    default:
    +        AnalysisAssertMsg(false, "Unexpected type in Lowerer::GetMissingItemOpndForCompare");
    +        __assume(false);
    +    }
     }
     
     bool
    @@ -18631,13 +18681,11 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
                     //
                     //     cmp  [segment + index], Js::SparseArraySegment::MissingValue
                     //     je   $helper
    -                InsertCompareBranch(
    +                InsertMissingItemCompareBranch(
                         indirOpnd,
    -                    GetMissingItemOpnd(src->GetType(), m_func),
                         Js::OpCode::BrEq_A,
                         labelHelper,
    -                    stElem,
    -                    true);
    +                    stElem);
                 }
                 else
                 {
    @@ -28023,6 +28071,13 @@ Lowerer::AddBailoutToHelperCallInstr(IR::Instr * helperCallInstr, BailOutInfo *
         return helperCallInstr;
     }
     
    +void
    +Lowerer::InsertAndLegalize(IR::Instr * instr, IR::Instr* insertBeforeInstr)
    +{
    +    insertBeforeInstr->InsertBefore(instr);
    +    LowererMD::Legalize(instr);
    +}
    +
     #if DBG
     void
     Lowerer::LegalizeVerifyRange(IR::Instr * instrStart, IR::Instr * instrLast)
    
  • lib/Backend/Lower.h+4 0 modified
    @@ -417,6 +417,8 @@ class Lowerer
     public:
         static IR::HelperCallOpnd*  CreateHelperCallOpnd(IR::JnHelperMethod helperMethod, int helperArgCount, Func* func);
         static IR::Opnd *           GetMissingItemOpnd(IRType type, Func *func);
    +    static IR::Opnd *           GetMissingItemOpndForAssignment(IRType type, Func *func);
    +    static IR::Opnd *           GetMissingItemOpndForCompare(IRType type, Func *func);
         static IR::Opnd *           GetImplicitCallFlagsOpnd(Func * func);
         inline static IR::IntConstOpnd* MakeCallInfoConst(ushort flags, int32 argCount, Func* func) {
             argCount = Js::CallInfo::GetArgCountWithoutExtraArgs((Js::CallFlags)flags, (uint16)argCount);
    @@ -430,6 +432,7 @@ class Lowerer
             return IR::IntConstOpnd::New(argCount | (flags << 24), TyMachReg, func, true);
     #endif
         }
    +    static void InsertAndLegalize(IR::Instr * instr, IR::Instr* insertBeforeInstr);
     private:
         IR::IndirOpnd* GenerateFastElemICommon(
             _In_ IR::Instr* elemInstr,
    @@ -516,6 +519,7 @@ class Lowerer
             _Inout_ IR::RegOpnd** taggedTypeOpnd);
     
         void            GenerateFastIsInSymbolOrStringIndex(IR::Instr * instrInsert, IR::RegOpnd *indexOpnd, IR::RegOpnd *baseOpnd, IR::Opnd *dest, uint32 inlineCacheOffset, const uint32 hitRateOffset, IR::LabelInstr * labelHelper, IR::LabelInstr * labelDone);
    +    IR::BranchInstr* InsertMissingItemCompareBranch(IR::Opnd* compareSrc, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr);
         bool            GenerateFastLdElemI(IR::Instr *& ldElem, bool *instrIsInHelperBlockRef);
         bool            GenerateFastStElemI(IR::Instr *& StElem, bool *instrIsInHelperBlockRef);
         bool            GenerateFastLdLen(IR::Instr *ldLen, bool *instrIsInHelperBlockRef);
    
  • lib/Backend/LowerMDShared.cpp+6 0 modified
    @@ -8624,4 +8624,10 @@ LowererMD::InsertCmovCC(const Js::OpCode opCode, IR::Opnd * dst, IR::Opnd* src1,
         LowererMD::Legalize(instr);
     
         return instr;
    +}
    +
    +IR::BranchInstr*
    +LowererMD::InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr)
    +{
    +    return this->lowererMDArch.InsertMissingItemCompareBranch(compareSrc, missingItemOpnd, opcode, target, insertBeforeInstr);
     }
    \ No newline at end of file
    
  • lib/Backend/LowerMDShared.h+1 0 modified
    @@ -223,6 +223,7 @@ class LowererMD
                 void            EmitLoadFloatFromNumber(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr);
                 void            EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
                 static void     EmitNon32BitOvfCheck(IR::Instr *instr, IR::Instr *insertInstr, IR::LabelInstr* bailOutLabel);
    +            IR::BranchInstr* InsertMissingItemCompareBranch(IR::Opnd* compareSrc, IR::Opnd* missingItemOpnd, Js::OpCode opcode, IR::LabelInstr* target, IR::Instr* insertBeforeInstr);
     
                 static void     LowerInt4NegWithBailOut(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel);
                 static void     LowerInt4AddWithBailOut(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel);
    
  • lib/Backend/Opnd.h+1 0 modified
    @@ -226,6 +226,7 @@ class Opnd
         bool                IsUnsigned() const { return IRType_IsUnsignedInt(this->m_type); }
         int                 GetSize() const { return TySize[this->m_type]; }
         bool                IsInt64() const { return IRType_IsInt64(this->m_type); }
    +    bool                IsUint64() const { return this->m_type == TyUint64; }
         bool                IsInt32() const { return this->m_type == TyInt32; }
         bool                IsUInt32() const { return this->m_type == TyUint32; }
         bool                IsIntegral32() const { return IsInt32() || IsUInt32(); }
    
  • lib/Runtime/Library/JavascriptArray.cpp+6 5 modified
    @@ -27,8 +27,10 @@ using namespace Js;
             { 5, 0, 0 },    // allocate space for 5 elements for array of length 4,5
             { 8, 0, 0 },    // allocate space for 8 elements for array of length 6,7,8
         };
    +
    +    const Var JavascriptArray::MissingItem = (Var)FloatMissingItemPattern;
     #if defined(TARGET_64)
    -    const Var JavascriptArray::MissingItem = (Var)0x8000000280000002;
    +    const Var JavascriptArray::IntMissingItemVar = (Var)(((uint64)IntMissingItemPattern << 32) | (uint32)IntMissingItemPattern);
         uint JavascriptNativeIntArray::allocationBuckets[][AllocationBucketsInfoSize] =
         {
             // See comments above on how to read this
    @@ -44,7 +46,7 @@ using namespace Js;
             {8, 0, 0},
         };
     #else
    -    const Var JavascriptArray::MissingItem = (Var)0x80000002;
    +    const Var JavascriptArray::IntMissingItemVar = (Var)IntMissingItemPattern;
         uint JavascriptNativeIntArray::allocationBuckets[][AllocationBucketsInfoSize] =
         {
             // See comments above on how to read this
    @@ -60,8 +62,7 @@ using namespace Js;
         };
     #endif
     
    -    const int32 JavascriptNativeIntArray::MissingItem = 0x80000002;
    -    static const uint64 FloatMissingItemPattern = 0x8000000280000002ull;
    +    const int32 JavascriptNativeIntArray::MissingItem = IntMissingItemPattern;
         const double JavascriptNativeFloatArray::MissingItem = *(double*)&FloatMissingItemPattern;
     
         // Allocate enough space for 4 inline property slots and 16 inline element slots
    @@ -12769,7 +12770,7 @@ using namespace Js;
                     return TypeIds_NativeIntArray;
                 }
             }
    -        if (JavascriptNumber::Is_NoTaggedIntCheck(value))
    +        else if (JavascriptNumber::Is_NoTaggedIntCheck(value))
             {
                 bool isInt32;
                 int32 i;
    
  • lib/Runtime/Library/JavascriptArray.h+1 0 modified
    @@ -140,6 +140,7 @@ namespace Js
     #endif
             static uint allocationBuckets[AllocationBucketsCount][AllocationBucketsInfoSize];
             static const Var MissingItem;
    +        static const Var IntMissingItemVar;
             template<typename T> static T GetMissingItem();
     
             SparseArraySegmentBase * GetHead() const { return head; }
    
  • lib/Runtime/Library/SparseArraySegment.h+12 4 modified
    @@ -89,6 +89,7 @@ namespace Js
             static SparseArraySegment<T>* CopySegment(Recycler *recycler, SparseArraySegment<T>* dst, uint32 dstIndex, SparseArraySegment<T>* src, uint32 srcIndex, uint32 inputLen);
     
             static T GetMissingItem();
    +        static Var GetMissingItemVar();
             static bool IsMissingItem(const T* value);
     
             template <class S>
    @@ -131,20 +132,27 @@ namespace Js
         template<>
         inline int32 SparseArraySegment<int32>::GetMissingItem()
         {
    -        return 0x80000002;
    +        return IntMissingItemPattern;
         }
     
         template<>
         inline double SparseArraySegment<double>::GetMissingItem()
         {
    -        uint64 u = 0x8000000280000002;
    -        return *(double*)&u;
    +        return *(double*)&FloatMissingItemPattern;
         }
     
    +    template<typename T>
    +    Var SparseArraySegment<T>::GetMissingItemVar()
    +    {
    +        return JavascriptArray::MissingItem;
    +    }
    +    template<>
    +    Var SparseArraySegment<int32>::GetMissingItemVar();
    +
         template<>
         inline bool SparseArraySegment<double>::IsMissingItem(const double* value)
         {
    -        return *(uint64*)value == 0x8000000280000002ull;
    +        return *(uint64*)value == FloatMissingItemPattern;
         }
     
         template<typename T>
    
  • lib/Runtime/Library/SparseArraySegment.inl+7 1 modified
    @@ -223,12 +223,18 @@ namespace Js
             return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
         }
     
    +    template<>
    +    inline Var SparseArraySegment<int32>::GetMissingItemVar()
    +    {
    +        return JavascriptArray::IntMissingItemVar;
    +    }
    +
         template<typename T>
         void SparseArraySegment<T>::FillSegmentBuffer(uint32 start, uint32 size)
         {
             // Fill the segment buffer using gp-register-sized stores. Avoid using the FPU for the sake
             // of perf (especially x86).
    -        Var fill = JavascriptArray::MissingItem;
    +        Var fill = (Var)SparseArraySegment<T>::GetMissingItemVar();
             if (sizeof(Var) > sizeof(T))
             {
                 // Pointer size is greater than the element (int32 buffer on x64).
    
  • lib/Runtime/RuntimeCommon.h+2 0 modified
    @@ -180,6 +180,8 @@ namespace Js
     #if FLOATVAR
         const uint64 FloatTag_Value       = 0xFFFCull << 48;
     #endif
    +    const uint64 FloatMissingItemPattern = 0xFFF80002FFF80002;
    +    const int32 IntMissingItemPattern = 0xFFF80002;
         template <bool IsPrototypeTemplate> class NullTypeHandler;
     
         template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported> class SimpleDictionaryTypeHandlerBase;
    

Vulnerability mechanics

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

References

9

News mentions

0

No linked articles in our index yet.