VYPR
Critical severity9.8NVD Advisory· Published Aug 11, 2017· Updated May 13, 2026

CVE-2017-8658

CVE-2017-8658

Description

A remote code execution vulnerability exists in the way that the Chakra JavaScript engine renders when handling objects in memory, aka "Scripting Engine Memory Corruption Vulnerability".

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.6.11.6.1

Affected products

2
  • Microsoft Corporation/ChakraCorev5
    Range: ChakraCore V1.7.1
  • cpe:2.3:a:microsoft:chakracore:*:*:*:*:*:*:*:*
    Range: <=1.7.0

Patches

1
2500e1cdc12c

17-08 ChakraCore servicing release

https://github.com/chakra-core/ChakraCorePaul LeathersAug 9, 2017via ghsa
78 files changed · +1385 344
  • Build/Chakra.Build.props+1 0 modified
    @@ -4,6 +4,7 @@
       <PropertyGroup>
         <Win32_WinNTVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_Win7)'">0x0601</Win32_WinNTVersion>
         <Win32_WinNTVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_Win8)'">0x0602</Win32_WinNTVersion>
    +    <Win32_WinNTVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_WinBlue)'">0x0603</Win32_WinNTVersion>
         <Win32_WinNTVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_Win10)'">0x0A00</Win32_WinNTVersion>
       </PropertyGroup>
       <PropertyGroup>
    
  • Build/Common.Build.Default.props+1 0 modified
    @@ -4,6 +4,7 @@
       <PropertyGroup>
         <NtTargetVersion_Win7 >0x601</NtTargetVersion_Win7>
         <NtTargetVersion_Win8 >0x602</NtTargetVersion_Win8>
    +    <NtTargetVersion_WinBlue>0x603</NtTargetVersion_WinBlue>
         <NtTargetVersion_Win10>0xA00</NtTargetVersion_Win10>
       </PropertyGroup>
     
    
  • Build/Common.Build.props+3 0 modified
    @@ -29,6 +29,8 @@
           <!-- ======== sources.inc ======== -->
           <!-- generates SAL annotations for our interface -->
           <AdditionalOptions>%(AdditionalOptions) -sal_local</AdditionalOptions>
    +      
    +      <PreprocessorDefinitions>%(PreprocessorDefinitions);WINVER=$(Win32_WinNTVersion)</PreprocessorDefinitions>
         </Midl>
         <ClCompile>
           <PreprocessorDefinitions>%(PreprocessorDefinitions);NOMINMAX;USE_EDGEMODE_JSRT</PreprocessorDefinitions>
    @@ -105,6 +107,7 @@
     
           <MinimumRequiredVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_Win7)'" >6.1</MinimumRequiredVersion>
           <MinimumRequiredVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_Win8)'" >6.2</MinimumRequiredVersion>
    +      <MinimumRequiredVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_WinBlue)'" >6.3</MinimumRequiredVersion>
           <MinimumRequiredVersion Condition="'$(NtTargetVersion)'=='$(NtTargetVersion_Win10)'" >10.00</MinimumRequiredVersion>
     
           <!-- Always set the checksum -->
    
  • lib/Backend/arm/LowerMD.cpp+1 1 modified
    @@ -8559,7 +8559,7 @@ LowererMD::LoadFloatValue(IR::Opnd * opndDst, double value, IR::Instr * instrIns
     #if DBG
                 NativeCodeData::GetDataDescription(pValue, instrInsert->m_func->m_alloc),
     #endif
    -            instrInsert->m_func);
    +            instrInsert->m_func, true);
         }
         else
         {
    
  • lib/Backend/AsmJsJITInfo.cpp+1 1 modified
    @@ -60,7 +60,7 @@ AsmJsJITInfo::GetArgTypeArray() const
     Js::AsmJsVarType::Which
     AsmJsJITInfo::GetArgType(Js::ArgSlot argNum) const
     {
    -    Assert(argNum < GetArgCount());
    +    AssertOrFailFast(argNum < GetArgCount());
         return GetArgTypeArray()[argNum];
     }
     
    
  • lib/Backend/AsmJsJITInfo.h+1 1 modified
    @@ -28,7 +28,6 @@ class AsmJsJITInfo
         Js::ArgSlot GetArgCount() const;
         Js::ArgSlot GetArgByteSize() const;
         Js::AsmJsRetType::Which GetRetType() const;
    -    Js::AsmJsVarType::Which * GetArgTypeArray() const;
         Js::AsmJsVarType::Which GetArgType(Js::ArgSlot argNum) const;
     
     #ifdef ENABLE_WASM
    @@ -40,6 +39,7 @@ class AsmJsJITInfo
         bool AccessNeedsBoundCheck(uint offset) const;
     
     private:
    +    Js::AsmJsVarType::Which * GetArgTypeArray() const;
         AsmJsDataIDL m_data;
     #endif
     };
    
  • lib/Backend/CodeGenWorkItem.h+7 0 modified
    @@ -58,6 +58,13 @@ struct CodeGenWorkItem : public JsUtil::Job
             return functionBody->GetScriptContext();
         }
     
    +    uint GetByteCodeLength() const
    +    {
    +        return this->functionBody->IsInDebugMode()
    +            ? this->functionBody->GetOriginalByteCode()->GetLength()
    +            : this->functionBody->GetByteCode()->GetLength();
    +    }
    +
         Js::FunctionBody* GetFunctionBody() const
         {
             return functionBody;
    
  • lib/Backend/Func.cpp+8 0 modified
    @@ -153,6 +153,14 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
     
         Assert(this->IsInlined() == !!runtimeInfo);
     
    +    AssertOrFailFast(!HasProfileInfo() || GetReadOnlyProfileInfo()->GetLoopCount() == GetJITFunctionBody()->GetLoopCount());
    +    Js::RegSlot tmpResult;
    +    AssertOrFailFast(!UInt32Math::Add(GetJITFunctionBody()->GetConstCount(), GetJITFunctionBody()->GetVarCount(), &tmpResult));
    +    AssertOrFailFast(GetJITFunctionBody()->IsAsmJsMode() || GetJITFunctionBody()->GetFirstTmpReg() <= GetJITFunctionBody()->GetLocalsCount());
    +    AssertOrFailFast(!IsLoopBody() || m_workItem->GetLoopNumber() < GetJITFunctionBody()->GetLoopCount());
    +    AssertOrFailFast(CONFIG_FLAG(Prejit) || CONFIG_ISENABLED(Js::ForceNativeFlag) || GetJITFunctionBody()->GetByteCodeLength() < (uint)CONFIG_FLAG(MaxJITFunctionBytecodeByteLength));
    +    GetJITFunctionBody()->EnsureConsistentConstCount();
    +
         if (this->IsTopFunc())
         {
             outputData->hasJittedStackClosure = false;
    
  • lib/Backend/IRBuilderAsmJs.cpp+22 11 modified
    @@ -27,7 +27,7 @@ IRBuilderAsmJs::Build()
         m_switchBuilder.Init(m_func, m_tempAlloc, true);
     
         m_firstVarConst = 0;
    -    Js::RegSlot tempCount = 0;
    +    m_tempCount = 0;
         m_firstsType[0] = m_firstVarConst + AsmJsRegSlots::RegCount;
         for (int i = 0, j = 1; i < WAsmJs::LIMIT; ++i, ++j)
         {
    @@ -36,7 +36,7 @@ IRBuilderAsmJs::Build()
             m_firstsType[j] = typedInfo.constCount;
             m_firstsType[j + WAsmJs::LIMIT] = typedInfo.varCount;
             m_firstsType[j + 2 * WAsmJs::LIMIT] = typedInfo.tmpCount;
    -        tempCount += typedInfo.tmpCount;
    +        m_tempCount += typedInfo.tmpCount;
         }
         // Fixup the firsts by looking at the previous value
         for (int i = 1; i < m_firstsTypeCount; ++i)
    @@ -66,10 +66,10 @@ IRBuilderAsmJs::Build()
         // we will be using lower space for type specialized syms, so bump up where new temp syms can be created
         m_func->m_symTable->IncreaseStartingID(m_firstIRTemp - m_func->m_symTable->GetMaxSymID());
     
    -    if (tempCount > 0)
    +    if (m_tempCount > 0)
         {
    -        m_tempMap = (SymID*)m_tempAlloc->AllocZero(sizeof(SymID) * tempCount);
    -        m_fbvTempUsed = BVFixed::New<JitArenaAllocator>(tempCount, m_tempAlloc);
    +        m_tempMap = AnewArrayZ(m_tempAlloc, SymID, m_tempCount);
    +        m_fbvTempUsed = BVFixed::New<JitArenaAllocator>(m_tempCount, m_tempAlloc);
         }
         else
         {
    @@ -359,9 +359,10 @@ IRBuilderAsmJs::BuildIntConstOpnd(Js::RegSlot regSlot)
         Js::Var * constTable = (Js::Var*)m_func->GetJITFunctionBody()->GetConstTable();
         const WAsmJs::TypedSlotInfo& info = m_func->GetJITFunctionBody()->GetAsmJsInfo()->GetTypedSlotInfo(WAsmJs::INT32);
         Assert(info.constSrcByteOffset != Js::Constants::InvalidOffset);
    +    AssertOrFailFast(info.constSrcByteOffset < UInt32Math::Mul<sizeof(Js::Var)>(m_func->GetJITFunctionBody()->GetConstCount()));
         int* intConstTable = reinterpret_cast<int*>(((byte*)constTable) + info.constSrcByteOffset);
         Js::RegSlot srcReg = GetTypedRegFromRegSlot(regSlot, WAsmJs::INT32);
    -    Assert(srcReg >= Js::FunctionBody::FirstRegSlot && srcReg < info.constCount);
    +    AssertOrFailFast(srcReg >= Js::FunctionBody::FirstRegSlot && srcReg < info.constCount);
         const int32 value = intConstTable[srcReg];
         IR::IntConstOpnd *opnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
     
    @@ -536,7 +537,9 @@ IRBuilderAsmJs::GetMappedTemp(Js::RegSlot reg)
         AssertMsg(RegIsTemp(reg), "Processing non-temp reg as a temp?");
         AssertMsg(m_tempMap, "Processing non-temp reg without a temp map?");
     
    -    return m_tempMap[reg - GetFirstTmp(WAsmJs::FirstType)];
    +    Js::RegSlot tempIndex = reg - GetFirstTmp(WAsmJs::FirstType);
    +    AssertOrFailFast(tempIndex < m_tempCount);
    +    return m_tempMap[tempIndex];
     }
     
     void
    @@ -545,7 +548,9 @@ IRBuilderAsmJs::SetMappedTemp(Js::RegSlot reg, SymID tempId)
         AssertMsg(RegIsTemp(reg), "Processing non-temp reg as a temp?");
         AssertMsg(m_tempMap, "Processing non-temp reg without a temp map?");
     
    -    m_tempMap[reg - GetFirstTmp(WAsmJs::FirstType)] = tempId;
    +    Js::RegSlot tempIndex = reg - GetFirstTmp(WAsmJs::FirstType);
    +    AssertOrFailFast(tempIndex < m_tempCount);
    +    m_tempMap[tempIndex] = tempId;
     }
     
     BOOL
    @@ -554,7 +559,9 @@ IRBuilderAsmJs::GetTempUsed(Js::RegSlot reg)
         AssertMsg(RegIsTemp(reg), "Processing non-temp reg as a temp?");
         AssertMsg(m_fbvTempUsed, "Processing non-temp reg without a used BV?");
     
    -    return m_fbvTempUsed->Test(reg - GetFirstTmp(WAsmJs::FirstType));
    +    Js::RegSlot tempIndex = reg - GetFirstTmp(WAsmJs::FirstType);
    +    AssertOrFailFast(tempIndex < m_tempCount);
    +    return m_fbvTempUsed->Test(tempIndex);
     }
     
     void
    @@ -563,13 +570,15 @@ IRBuilderAsmJs::SetTempUsed(Js::RegSlot reg, BOOL used)
         AssertMsg(RegIsTemp(reg), "Processing non-temp reg as a temp?");
         AssertMsg(m_fbvTempUsed, "Processing non-temp reg without a used BV?");
     
    +    Js::RegSlot tempIndex = reg - GetFirstTmp(WAsmJs::FirstType);
    +    AssertOrFailFast(tempIndex < m_tempCount);
         if (used)
         {
    -        m_fbvTempUsed->Set(reg - GetFirstTmp(WAsmJs::FirstType));
    +        m_fbvTempUsed->Set(tempIndex);
         }
         else
         {
    -        m_fbvTempUsed->Clear(reg - GetFirstTmp(WAsmJs::FirstType));
    +        m_fbvTempUsed->Clear(tempIndex);
         }
     }
     
    @@ -697,6 +706,8 @@ void IRBuilderAsmJs::CreateLoadConstInstrForType(
     )
     {
         T* typedTable = (T*)(table + byteOffset);
    +    AssertOrFailFast(byteOffset < UInt32Math::Mul<sizeof(Js::Var)>(m_func->GetJITFunctionBody()->GetConstCount()));
    +    AssertOrFailFast(AllocSizeMath::Add((size_t)typedTable, UInt32Math::Mul<sizeof(T)>(constCount)) <= (size_t)((Js::Var*)m_func->GetJITFunctionBody()->GetConstTable() + m_func->GetJITFunctionBody()->GetConstCount()));
         // 1 for return register
         ++regAllocated;
         ++typedTable;
    
  • lib/Backend/IRBuilderAsmJs.h+2 0 modified
    @@ -172,6 +172,8 @@ class IRBuilderAsmJs
         Js::RegSlot             m_firstsType[m_firstsTypeCount];
         Js::RegSlot             m_firstVarConst;
         Js::RegSlot             m_firstIRTemp;
    +    Js::RegSlot             m_tempCount;
    +
         Js::OpCode *            m_simdOpcodesMap;
     
         Js::RegSlot GetFirstConst(WAsmJs::Types type) { return m_firstsType[type]; }
    
  • lib/Backend/IRBuilder.cpp+4 1 modified
    @@ -400,7 +400,7 @@ IRBuilder::Build()
         Js::RegSlot tempCount = m_func->GetJITFunctionBody()->GetTempCount();
         if (tempCount > 0)
         {
    -        this->tempMap = (SymID*)m_tempAlloc->AllocZero(sizeof(SymID) * tempCount);
    +        this->tempMap = AnewArrayZ(m_tempAlloc, SymID, tempCount);
             this->fbvTempUsed = BVFixed::New<JitArenaAllocator>(tempCount, m_tempAlloc);
         }
         else
    @@ -446,6 +446,7 @@ IRBuilder::Build()
     #endif
     
             lastOffset = m_func->m_workItem->GetLoopHeader()->endOffset;
    +        AssertOrFailFast(lastOffset < m_func->GetJITFunctionBody()->GetByteCodeLength());
             // Ret is created at lastOffset + 1, so we need lastOffset + 2 entries
             offsetToInstructionCount = lastOffset + 2;
     
    @@ -2721,6 +2722,7 @@ IRBuilder::BuildUnsigned1(Js::OpCode newOpcode, uint32 offset, uint32 num)
     
             case Js::OpCode::ProfiledLoopStart:
             {
    +            AssertOrFailFast(num < m_func->GetJITFunctionBody()->GetLoopCount());
                 // If we're in profiling SimpleJit and jitting loop bodies, we need to keep this until lowering.
                 if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
                 {
    @@ -2771,6 +2773,7 @@ IRBuilder::BuildUnsigned1(Js::OpCode newOpcode, uint32 offset, uint32 num)
     
             case Js::OpCode::ProfiledLoopEnd:
             {
    +            AssertOrFailFast(num < m_func->GetJITFunctionBody()->GetLoopCount());
                 // TODO: Decide whether we want the implicit loop call flags to be recorded in simplejitted loop bodies
                 if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
                 {
    
  • lib/Backend/IRBuilder.h+13 5 modified
    @@ -225,37 +225,45 @@ class IRBuilder
             AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
             AssertMsg(this->tempMap, "Processing non-temp reg without a temp map?");
     
    -        return this->tempMap[reg - this->firstTemp];
    +        Js::RegSlot tempIndex = reg - this->firstTemp;
    +        AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
    +        return this->tempMap[tempIndex];
         }
     
         void                SetMappedTemp(Js::RegSlot reg, SymID tempId)
         {
             AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
             AssertMsg(this->tempMap, "Processing non-temp reg without a temp map?");
     
    -        this->tempMap[reg - this->firstTemp] = tempId;
    +        Js::RegSlot tempIndex = reg - this->firstTemp;
    +        AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
    +        this->tempMap[tempIndex] = tempId;
         }
     
         BOOL                GetTempUsed(Js::RegSlot reg)
         {
             AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
             AssertMsg(this->fbvTempUsed, "Processing non-temp reg without a used BV?");
     
    -        return this->fbvTempUsed->Test(reg - this->firstTemp);
    +        Js::RegSlot tempIndex = reg - this->firstTemp;
    +        AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
    +        return this->fbvTempUsed->Test(tempIndex);
         }
     
         void                SetTempUsed(Js::RegSlot reg, BOOL used)
         {
             AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
             AssertMsg(this->fbvTempUsed, "Processing non-temp reg without a used BV?");
     
    +        Js::RegSlot tempIndex = reg - this->firstTemp;
    +        AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
             if (used)
             {
    -            this->fbvTempUsed->Set(reg - this->firstTemp);
    +            this->fbvTempUsed->Set(tempIndex);
             }
             else
             {
    -            this->fbvTempUsed->Clear(reg - this->firstTemp);
    +            this->fbvTempUsed->Clear(tempIndex);
             }
         }
     
    
  • lib/Backend/IR.cpp+6 0 modified
    @@ -84,6 +84,12 @@ Instr::HasEquivalentTypeCheckBailOut() const
         return this->HasBailOutInfo() && IR::IsEquivalentTypeCheckBailOutKind(this->GetBailOutKind());
     }
     
    +bool
    +Instr::HasBailOnNoProfile() const
    +{
    +    return this->HasBailOutInfo() && this->GetBailOutKind() == IR::BailOutOnNoProfile;
    +}
    +
     void
     Instr::ChangeEquivalentToMonoTypeCheckBailOut()
     {
    
  • lib/Backend/IR.h+1 0 modified
    @@ -203,6 +203,7 @@ class Instr
         bool            HasAuxBailOut() const { return hasAuxBailOut; }
         bool            HasTypeCheckBailOut() const;
         bool            HasEquivalentTypeCheckBailOut() const;
    +    bool            HasBailOnNoProfile() const;
         void            ClearBailOutInfo();
         bool            IsDstNotAlwaysConvertedToInt32() const;
         bool            IsDstNotAlwaysConvertedToNumber() const;
    
  • lib/Backend/JITTimeFunctionBody.cpp+16 1 modified
    @@ -870,6 +870,19 @@ JITTimeFunctionBody::GetConstantContent(Js::RegSlot location) const
         return obj;
     }
     
    +void
    +JITTimeFunctionBody::EnsureConsistentConstCount() const
    +{
    +    if (GetConstCount() == 0 || IsAsmJsMode())
    +    {
    +        AssertOrFailFast(m_bodyData.constTableContent == nullptr);
    +    }
    +    else
    +    {
    +        AssertOrFailFast(m_bodyData.constTableContent != nullptr && GetConstCount() == m_bodyData.constTableContent->count);
    +    }
    +}
    +
     intptr_t
     JITTimeFunctionBody::GetInlineCache(uint index) const
     {
    @@ -1059,20 +1072,22 @@ JITTimeFunctionBody::GetAuxDataAddr(uint offset) const
     void *
     JITTimeFunctionBody::ReadFromAuxData(uint offset) const
     {
    +    AssertOrFailFast(offset < m_bodyData.auxDataCount);
         return (void *)(m_bodyData.auxData + offset);
     }
     
     void *
     JITTimeFunctionBody::ReadFromAuxContextData(uint offset) const
     {
    +    AssertOrFailFast(offset < m_bodyData.auxContextDataCount);
         return (void *)(m_bodyData.auxContextData + offset);
     }
     
     const Js::PropertyIdArray *
     JITTimeFunctionBody::ReadPropertyIdArrayFromAuxData(uint offset) const
     {
         Js::PropertyIdArray * auxArray = (Js::PropertyIdArray *)(m_bodyData.auxData + offset);
    -    Assert(offset + auxArray->GetDataSize() <= m_bodyData.auxDataCount);
    +    AssertOrFailFast(AllocSizeMath::Add(offset, auxArray->GetDataSize()) <= m_bodyData.auxDataCount);
         return auxArray;
     }
     
    
  • lib/Backend/JITTimeFunctionBody.h+1 0 modified
    @@ -98,6 +98,7 @@ class JITTimeFunctionBody
         bool CanInlineRecursively(uint depth, bool tryAggressive = true) const;
         bool NeedScopeObjectForArguments(bool hasNonSimpleParams) const;
         bool GetDoScopeObjectCreation() const;
    +    void EnsureConsistentConstCount() const;
     
         const byte * GetByteCodeBuffer() const;
         StatementMapIDL * GetFullStatementMap() const;
    
  • lib/Backend/JITTimeProfileInfo.h+2 1 modified
    @@ -34,6 +34,8 @@ class JITTimeProfileInfo
         Js::ImplicitCallFlags GetImplicitCallFlags() const;
         Js::LoopFlags GetLoopFlags(uint loopNum) const;
     
    +    uint GetLoopCount() const;
    +
         uint16 GetConstantArgInfo(Js::ProfileId callSiteId) const;
     
         bool IsModulusOpByPowerOf2(Js::ProfileId profileId) const;
    @@ -116,7 +118,6 @@ class JITTimeProfileInfo
         Js::ProfileId GetProfiledSlotCount() const;
         Js::ArgSlot GetProfiledInParamsCount() const;
         uint GetProfiledFldCount() const;
    -    uint GetLoopCount() const;
         BVFixed * GetLoopFlags() const;
     
         bool TestFlag(ProfileDataFlags flag) const;
    
  • lib/Backend/LinearScan.cpp+1 1 modified
    @@ -3632,7 +3632,7 @@ void LinearScan::TrackInlineeArgLifetimes(IR::Instr* instr)
                 Assert(this->currentBlock->inlineeStack.Count() == 0);
             }
         }
    -    else if (instr->m_opcode == Js::OpCode::InlineeEnd)
    +    else if (instr->m_opcode == Js::OpCode::InlineeEnd || instr->HasBailOnNoProfile())
         {
             if (instr->m_func->m_hasInlineArgsOpt)
             {
    
  • lib/Backend/Lower.cpp+4 4 modified
    @@ -7138,7 +7138,7 @@ Lowerer::GenerateCachedTypeCheck(IR::Instr *instrChk, IR::PropertySymOpnd *prope
     #if DBG
                     NativeCodeData::GetDataDescription(typeCheckGuard, func->m_alloc),
     #endif
    -                func);
    +                func, true);
                 this->addToLiveOnBackEdgeSyms->Set(func->GetTopFunc()->GetNativeCodeDataSym()->m_id);
             }
             else
    @@ -7311,7 +7311,7 @@ Lowerer::GenerateCachedTypeWithoutPropertyCheck(IR::Instr *instrInsert, IR::Prop
     #if DBG
                     NativeCodeData::GetDataDescription(typePropertyGuard, this->m_func->m_alloc),
     #endif
    -                this->m_func);
    +                this->m_func, true);
     
                 this->addToLiveOnBackEdgeSyms->Set(m_func->GetTopFunc()->GetNativeCodeDataSym()->m_id);
             }
    @@ -9471,7 +9471,7 @@ IR::Instr* Lowerer::LowerMultiBr(IR::Instr * instr, IR::JnHelperMethod helperMet
     #if DBG
                     NativeCodeData::GetDataDescription(dictionary, this->m_func->m_alloc),
     #endif
    -                this->m_func), instr);
    +                this->m_func, true), instr);
     
             this->addToLiveOnBackEdgeSyms->Set(m_func->GetTopFunc()->GetNativeCodeDataSym()->m_id);
     
    @@ -13145,7 +13145,7 @@ Lowerer::GenerateBailOut(IR::Instr * instr, IR::BranchInstr * branchInstr, IR::L
     #if DBG
                     NativeCodeData::GetDataDescription(bailOutInfo->bailOutRecord, this->m_func->m_alloc),
     #endif
    -                m_func);
    +                m_func, true);
     
                 this->addToLiveOnBackEdgeSyms->Set(m_func->GetTopFunc()->GetNativeCodeDataSym()->m_id);
             }
    
  • lib/Backend/LowerMDShared.cpp+2 2 modified
    @@ -6201,7 +6201,7 @@ LowererMD::EmitLoadFloatCommon(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertIn
     #if DBG
                     NativeCodeData::GetDataDescription(pDouble, m_func->m_alloc),
     #endif
    -                m_func);
    +                m_func, true);
     
                 GetLowerer()->addToLiveOnBackEdgeSyms->Set(m_func->GetTopFunc()->GetNativeCodeDataSym()->m_id);
             }
    @@ -7037,7 +7037,7 @@ LowererMD::LoadFloatValue(IR::Opnd * opndDst, double value, IR::Instr * instrIns
     #if DBG
                 NativeCodeData::GetDataDescription(pValue, instrInsert->m_func->m_alloc),
     #endif
    -            instrInsert->m_func);
    +            instrInsert->m_func, true);
         }
     
         // movsd xmm, [reg+offset]
    
  • lib/Backend/LowerMDSharedSimd128.cpp+1 1 modified
    @@ -390,7 +390,7 @@ IR::Instr* LowererMD::Simd128LoadConst(IR::Instr* instr)
     #if DBG
                 NativeCodeData::GetDataDescription(pValue, m_func->m_alloc),
     #endif
    -            m_func);
    +            m_func, true);
     
             GetLowerer()->addToLiveOnBackEdgeSyms->Set(m_func->GetTopFunc()->GetNativeCodeDataSym()->m_id);
         }
    
  • lib/Backend/NativeCodeGenerator.cpp+2 1 modified
    @@ -1783,7 +1783,8 @@ NativeCodeGenerator::WorkItemExceedsJITLimits(CodeGenWorkItem *const codeGenWork
         return
             (codeGenWork->GetScriptContext()->GetThreadContext()->GetCodeSize() >= Js::Constants::MaxThreadJITCodeHeapSize) ||
             (ThreadContext::GetProcessCodeSize() >= Js::Constants::MaxProcessJITCodeHeapSize) ||
    -        (codeGenWork->GetByteCodeCount() >= (uint)CONFIG_FLAG(MaxJITFunctionBytecodeSize));
    +        (codeGenWork->GetByteCodeLength() >= (uint)CONFIG_FLAG(MaxJITFunctionBytecodeByteLength)) ||
    +        (codeGenWork->GetByteCodeCount() >= (uint)CONFIG_FLAG(MaxJITFunctionBytecodeCount));
     }
     bool
     NativeCodeGenerator::Process(JsUtil::Job *const job, JsUtil::ParallelThreadData *threadData)
    
  • lib/Backend/ObjTypeSpecFldInfo.cpp+11 2 modified
    @@ -114,6 +114,7 @@ Js::TypeId
     ObjTypeSpecFldInfo::GetTypeId(uint i) const
     {
         Assert(IsPoly());
    +    AssertOrFailFast(i < m_data.fixedFieldInfoArraySize);
         return (Js::TypeId)GetFixedFieldInfoArray()[i].GetType()->GetTypeId();
     }
     
    @@ -151,6 +152,7 @@ intptr_t
     ObjTypeSpecFldInfo::GetFieldValue(uint i) const
     {
         Assert(IsPoly());
    +    AssertOrFailFast(i < m_data.fixedFieldInfoArraySize);
         return GetFixedFieldInfoArray()[i].GetFieldValue();
     }
     
    @@ -164,6 +166,7 @@ intptr_t
     ObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
     {
         Assert(HasFixedValue() && GetFixedFieldCount() == 1);
    +    AssertOrFailFast(m_data.fixedFieldInfoArraySize > 0);
     
         return GetFixedFieldInfoArray()[0].GetFieldValue();
     }
    @@ -191,6 +194,7 @@ JITTypeHolder
     ObjTypeSpecFldInfo::GetType(uint i) const
     {
         Assert(i == 0 || IsPoly());
    +    AssertOrFailFast(i < m_data.fixedFieldInfoArraySize);
         JITType * type = GetFixedFieldInfoArray()[i].GetType();
         if (!type)
         {
    @@ -223,6 +227,7 @@ ObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
     {
         Assert(HasFixedValue());
         Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
    +    AssertOrFailFast(m_data.fixedFieldInfoArraySize > 0);
         Assert(GetFixedFieldInfoArray());
         if (GetFixedFieldInfoArray()[0].GetFuncInfoAddr() != 0)
         {
    @@ -236,9 +241,13 @@ ObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
     {
         Assert(HasFixedValue());
         Assert(IsPoly());
    -    if (m_data.fixedFieldCount > 0 && GetFixedFieldInfoArray()[i].GetFuncInfoAddr() != 0)
    +    if (m_data.fixedFieldCount > 0)
         {
    -        return &GetFixedFieldInfoArray()[i];
    +        AssertOrFailFast(i < m_data.fixedFieldInfoArraySize);
    +        if (GetFixedFieldInfoArray()[i].GetFuncInfoAddr() != 0)
    +        {
    +            return &GetFixedFieldInfoArray()[i];
    +        }
         }
         return nullptr;
     }
    
  • lib/Backend/SccLiveness.cpp+1 1 modified
    @@ -490,7 +490,7 @@ SCCLiveness::ProcessBailOutUses(IR::Instr * instr)
         // lifetimes wouldn't have been extended beyond the bailout point (InlineeEnd extends the lifetimes)
         // Extend argument lifetimes up to the bail out point to allow LinearScan::SpillInlineeArgs to spill
         // inlinee args.
    -    if ((instr->GetBailOutKind() == IR::BailOutOnNoProfile) && !instr->m_func->IsTopFunc())
    +    if (instr->HasBailOnNoProfile() && !instr->m_func->IsTopFunc())
         {
             Func * inlinee = instr->m_func;
             while (!inlinee->IsTopFunc())
    
  • lib/Backend/Security.cpp+243 104 modified
    @@ -13,29 +13,108 @@ Security::EncodeLargeConstants()
             return;
         }
     
    -    FOREACH_REAL_INSTR_IN_FUNC_EDITING(instr, instrNext, this->func)
    +    uint prevInstrConstSize = 0;
    +    FOREACH_INSTR_IN_FUNC_EDITING(instr, instrNext, this->func)
         {
             if (!instr->IsRealInstr())
             {
    +            if (instr->IsLabelInstr())
    +            {
    +                IR::LabelInstr * label = instr->AsLabelInstr();
    +
    +                if (label->labelRefs.Count() > 1 || (label->labelRefs.Count() == 1 && label->labelRefs.Head() != label->m_prev))
    +                {
    +                    if (this->cookieOpnd != nullptr)
    +                    {
    +                        this->cookieOpnd->Free(this->func);
    +                    }
    +                    this->baseOpnd = nullptr;
    +                    this->cookieOpnd = nullptr;
    +                    this->basePlusCookieOpnd = nullptr;
    +                }
    +            }
                 continue;
             }
    +
    +        IR::Opnd *src1 = instr->GetSrc1();
    +        IR::Opnd *src2 = instr->GetSrc2();
             IR::Opnd *dst = instr->GetDst();
    -        if (dst)
    +
    +        if (dst && this->baseOpnd && dst->IsEqual(this->baseOpnd))
             {
    -            this->EncodeOpnd(instr, dst);
    +            if (this->cookieOpnd != nullptr)
    +            {
    +                this->cookieOpnd->Free(this->func);
    +            }
    +            this->baseOpnd = nullptr;
    +            this->cookieOpnd = nullptr;
    +            this->basePlusCookieOpnd = nullptr;
             }
    -        IR::Opnd *src1 = instr->GetSrc1();
    +
    +        uint currInstrConstSize = 0;
    +        uint dstSize = dst ? CalculateConstSize(dst) : 0;
    +        uint src1Size = 0;
    +        uint src2Size = 0;
             if (src1)
             {
    -            this->EncodeOpnd(instr, src1);
    -
    -            IR::Opnd *src2 = instr->GetSrc2();
    +            src1Size = CalculateConstSize(src1);
                 if (src2)
                 {
    -                this->EncodeOpnd(instr, src2);
    +                src2Size = CalculateConstSize(src2);
    +            }
    +        }
    +
    +        prevInstrConstSize = currInstrConstSize;
    +        currInstrConstSize = dstSize + src1Size + src2Size;
    +
    +        // we don't need to blind constants if user controlled byte size < 3
    +        if (currInstrConstSize + prevInstrConstSize <= 2 && !PHASE_FORCE1(Js::EncodeConstantsPhase))
    +        {
    +            continue;
    +        }
    +
    +        bool isSrc1EqualDst = false;
    +        if (dstSize >= 2)
    +        {
    +            // don't count instrs where dst == src1 against size
    +            if (src1 && dstSize == src1Size && src1->IsEqual(dst))
    +            {
    +                currInstrConstSize -= dstSize;
    +                isSrc1EqualDst = true;
    +
    +                if (currInstrConstSize + prevInstrConstSize <= 2 && !PHASE_FORCE1(Js::EncodeConstantsPhase))
    +                {
    +                    continue;
    +                }
    +            }
    +
    +            this->EncodeOpnd(instr, dst);
    +            if (isSrc1EqualDst)
    +            {
    +                instr->ReplaceSrc1(dst);
    +            }
    +            currInstrConstSize -= dstSize;
    +            if (currInstrConstSize + prevInstrConstSize <= 2 && !PHASE_FORCE1(Js::EncodeConstantsPhase))
    +            {
    +                continue;
    +            }
    +        }
    +        if (src1Size >= 2 && !isSrc1EqualDst)
    +        {
    +            this->EncodeOpnd(instr, src1);
    +            currInstrConstSize -= src1Size;
    +            if (currInstrConstSize + prevInstrConstSize <= 2 && !PHASE_FORCE1(Js::EncodeConstantsPhase))
    +            {
    +                continue;
                 }
             }
    -    } NEXT_REAL_INSTR_IN_FUNC_EDITING;
    +        if (src2Size >= 2)
    +        {
    +            this->EncodeOpnd(instr, src2);
    +            currInstrConstSize -= src2Size;
    +        }
    +    } NEXT_INSTR_IN_FUNC_EDITING;
    +
     }
     
     int
    @@ -91,10 +170,10 @@ Security::InsertNOPs()
         int count = 0;
         IR::Instr *instr = this->func->m_headInstr;
     
    -    while(true)
    +    while (true)
         {
             count = this->GetNextNOPInsertPoint();
    -        while(instr && count--)
    +        while (instr && count--)
             {
                 instr = instr->GetNextRealInstr();
             }
    @@ -174,7 +253,7 @@ Security::InsertSmallNOP(IR::Instr * instr, DWORD nopSize)
     
         IR::Instr *nopInstr = nullptr;
     
    -    switch(nopSize)
    +    switch (nopSize)
         {
         case 1:
         case 2:
    @@ -210,29 +289,54 @@ Security::DontEncode(IR::Opnd *opnd)
         {
             IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();
             return (addrOpnd->m_dontEncode ||
    -                !addrOpnd->IsVar() ||
    -                addrOpnd->m_address == nullptr ||
    -                !Js::TaggedNumber::Is(addrOpnd->m_address));
    +            !addrOpnd->IsVar() ||
    +            addrOpnd->m_address == nullptr ||
    +            !Js::TaggedNumber::Is(addrOpnd->m_address));
         }
    -
    -    case IR::OpndKindHelperCall:
    -        // Never encode helper call addresses, as these are always internal constants.
    +    case IR::OpndKindIndir:
    +    {
    +        IR::IndirOpnd *indirOpnd = opnd->AsIndirOpnd();
    +        return indirOpnd->m_dontEncode || indirOpnd->GetOffset() == 0;
    +    }
    +    default:
             return true;
         }
    -
    -    return false;
     }
     
    -void
    -Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
    +uint
    +Security::CalculateConstSize(IR::Opnd *opnd)
     {
    -    IR::RegOpnd *newOpnd;
    -    bool isSrc2 = false;
    -
    -    if (Security::DontEncode(opnd))
    +    if (DontEncode(opnd))
         {
    -        return;
    +        return 0;
         }
    +    switch (opnd->GetKind())
    +    {
    +    case IR::OpndKindIntConst:
    +    {
    +        IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();
    +        return GetByteCount(intConstOpnd->GetValue());
    +    }
    +    case IR::OpndKindAddr:
    +    {
    +        IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();
    +        return Js::TaggedInt::Is(addrOpnd->m_address) ? GetByteCount(Js::TaggedInt::ToInt32(addrOpnd->m_address)) : GetByteCount((intptr_t)addrOpnd->m_address);
    +    }
    +    case IR::OpndKindIndir:
    +    {
    +        IR::IndirOpnd * indirOpnd = opnd->AsIndirOpnd();
    +        return GetByteCount(indirOpnd->GetOffset());
    +    }
    +    default:
    +        Assume(UNREACHED);
    +    }
    +    return 0;
    +}
    +bool
    +Security::EncodeOpnd(IR::Instr * instr, IR::Opnd *opnd)
    +{
    +    IR::RegOpnd *newOpnd;
    +    bool isSrc2 = false;
     
         const auto unlinkSrc = [&]() {
             if (opnd != instr->GetSrc1())
    @@ -247,38 +351,12 @@ Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
             }
         };
     
    -    switch(opnd->GetKind())
    -    {
    -    case IR::OpndKindInt64Const:
    +    switch (opnd->GetKind())
         {
    -#if TARGET_64
    -        IR::Int64ConstOpnd *intConstOpnd = opnd->AsInt64ConstOpnd();
    -        if (!this->IsLargeConstant(intConstOpnd->GetValue()))
    -        {
    -            return;
    -        }
    -        unlinkSrc();
    -        int64 encodedValue = EncodeValue(instr, intConstOpnd, intConstOpnd->GetValue(), &newOpnd);
    -        intConstOpnd->SetEncodedValue(encodedValue);
    -#else
    -        Assert(UNREACHED);
    -        return;
    -#endif
    -    }
    -    break;
    -
         case IR::OpndKindIntConst:
         {
             IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();
     
    -        if (
    -#if TARGET_64
    -            IRType_IsInt64(intConstOpnd->GetType()) ? !this->IsLargeConstant(intConstOpnd->GetValue()) :
    -#endif
    -            !this->IsLargeConstant(intConstOpnd->AsInt32()))
    -        {
    -            return;
    -        }
             unlinkSrc();
     
             intConstOpnd->SetEncodedValue(EncodeValue(instr, intConstOpnd, intConstOpnd->GetValue(), &newOpnd));
    @@ -289,12 +367,6 @@ Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
         {
             IR::AddrOpnd *addrOpnd = opnd->AsAddrOpnd();
     
    -        // Only encode large constants.  Small ones don't allow control of enough bits
    -        if (Js::TaggedInt::Is(addrOpnd->m_address) && !this->IsLargeConstant(Js::TaggedInt::ToInt32(addrOpnd->m_address)))
    -        {
    -            return;
    -        }
    -
             unlinkSrc();
     
             addrOpnd->SetEncodedValue((Js::Var)this->EncodeValue(instr, addrOpnd, (IntConstType)addrOpnd->m_address, &newOpnd), addrOpnd->GetAddrOpndKind());
    @@ -305,29 +377,63 @@ Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
         {
             IR::IndirOpnd *indirOpnd = opnd->AsIndirOpnd();
     
    -        if (!this->IsLargeConstant(indirOpnd->GetOffset()) || indirOpnd->m_dontEncode)
    +        // Using 32 bit cookie causes major perf loss on the subsequent indirs, so only support this path for 16 bit offset
    +        // It's relatively rare for base to be null or to have index + offset, so fall back to the more generic xor method for these
    +        if (indirOpnd->GetBaseOpnd() && indirOpnd->GetIndexOpnd() == nullptr && Math::FitsInWord(indirOpnd->GetOffset()))
             {
    -            return;
    +            if (!this->baseOpnd || !this->baseOpnd->IsEqual(indirOpnd->GetBaseOpnd()))
    +            {
    +                if (this->cookieOpnd != nullptr)
    +                {
    +                    this->cookieOpnd->Free(this->func);
    +                }
    +                this->cookieOpnd = BuildCookieOpnd(TyInt16, instr->m_func);
    +                this->basePlusCookieOpnd = IR::RegOpnd::New(TyMachReg, instr->m_func);
    +                this->baseOpnd = indirOpnd->GetBaseOpnd();
    +                IR::IndirOpnd * indir = IR::IndirOpnd::New(this->baseOpnd, this->cookieOpnd->AsInt32(), TyMachReg, instr->m_func);
    +                Lowerer::InsertLea(this->basePlusCookieOpnd, indir, instr);
    +            }
    +            int32 diff = indirOpnd->GetOffset() - this->cookieOpnd->AsInt32();
    +            indirOpnd->SetOffset((int32)diff);
    +            indirOpnd->SetBaseOpnd(this->basePlusCookieOpnd);
    +            return true;
             }
    -        AssertMsg(indirOpnd->GetIndexOpnd() == nullptr, "Code currently doesn't support indir with offset and indexOpnd");
     
    -        IR::IntConstOpnd *indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, instr->m_func);
    +        IR::IntConstOpnd *indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyMachReg, instr->m_func);
    +
    +        indexOpnd->SetValue(EncodeValue(instr, indexOpnd, indexOpnd->GetValue(), &newOpnd));
     
    -        indexOpnd->SetEncodedValue(EncodeValue(instr, indexOpnd, indexOpnd->GetValue(), &newOpnd));
             indirOpnd->SetOffset(0);
    -        indirOpnd->SetIndexOpnd(newOpnd);
    +        if (indirOpnd->GetIndexOpnd() != nullptr)
    +        {
    +            // update the base rather than the index, because index might have scale
    +            if (indirOpnd->GetBaseOpnd() != nullptr)
    +            {
    +                IR::RegOpnd * newBaseOpnd = IR::RegOpnd::New(TyMachReg, instr->m_func);
    +                Lowerer::InsertAdd(false, newBaseOpnd, newOpnd, indirOpnd->GetBaseOpnd(), instr);
    +                indirOpnd->SetBaseOpnd(newBaseOpnd);
    +            }
    +            else
    +            {
    +                indirOpnd->SetBaseOpnd(newOpnd);
    +            }
    +        }
    +        else
    +        {
    +            indirOpnd->SetIndexOpnd(newOpnd);
    +        }
         }
    -    return;
    +    return true;
     
         default:
    -        return;
    +        return false;
         }
     
         IR::Opnd *dst = instr->GetDst();
     
         if (dst)
         {
    -#if _M_X64
    +#if TARGET_64
             // Ensure the left and right operand has the same type (that might not be true for constants on x64)
             newOpnd = (IR::RegOpnd *)newOpnd->UseWithNewType(dst->GetType(), instr->m_func);
     #endif
    @@ -347,32 +453,70 @@ Security::EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd)
             }
         }
     
    -     LowererMD::ImmedSrcToReg(instr, newOpnd, isSrc2 ? 2 : 1);
    +    LowererMD::ImmedSrcToReg(instr, newOpnd, isSrc2 ? 2 : 1);
    +    return true;
    +}
    +
    +IR::IntConstOpnd *
    +Security::BuildCookieOpnd(IRType type, Func * func)
    +{
    +    IntConstType cookie = 0;
    +    switch (type)
    +    {
    +    case TyInt8:
    +        cookie = (int8)Math::Rand();
    +        break;
    +    case TyUint8:
    +        cookie = (uint8)Math::Rand();
    +        break;
    +    case TyInt16:
    +        cookie = (int16)Math::Rand();
    +        break;
    +    case TyUint16:
    +        cookie = (uint16)Math::Rand();
    +        break;
    +#if TARGET_32
    +    case TyVar:
    +#endif
    +    case TyInt32:
    +        cookie = (int32)Math::Rand();
    +        break;
    +    case TyUint32:
    +        cookie = (uint32)Math::Rand();
    +        break;
    +#if TARGET_64
    +    case TyVar:
    +    case TyInt64:
    +    case TyUint64:
    +        cookie = Math::Rand();
    +        break;
    +#endif
    +    default:
    +        Assume(UNREACHED);
    +    }
    +    IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, type, func);
    +
    +#if DBG_DUMP
    +    cookieOpnd->SetName(_u("cookie"));
    +#endif
    +    return cookieOpnd;
     }
     
     IntConstType
    -Security::EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue, IR::RegOpnd **pNewOpnd)
    +Security::EncodeValue(IR::Instr * instr, IR::Opnd *opnd, IntConstType constValue, _Out_ IR::RegOpnd **pNewOpnd)
     {
         if (opnd->GetType() == TyInt32 || opnd->GetType() == TyInt16 || opnd->GetType() == TyInt8
    -#if _M_IX86
    +#if TARGET_32
             || opnd->GetType() == TyVar
     #endif
             )
         {
    -        int32 cookie = (int32)Math::Rand();
    -        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(TyInt32, instr->m_func), TyInt32, instr->m_func);
    +        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(opnd->GetType(), instr->m_func), opnd->GetType(), instr->m_func);
             IR::Instr * instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);
    -
    -        IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, TyInt32, instr->m_func);
    -
    -#if DBG_DUMP
    -        cookieOpnd->SetName(_u("cookie"));
    -#endif
    -
    -        instrNew = IR::Instr::New(Js::OpCode::Xor_I4, regOpnd, regOpnd, cookieOpnd, instr->m_func);
    +        IR::IntConstOpnd * cookieOpnd = BuildCookieOpnd(opnd->GetType(), instr->m_func);
    +        instrNew = IR::Instr::New(LowererMD::MDXorOpcode, regOpnd, regOpnd, cookieOpnd, instr->m_func);
             instr->InsertBefore(instrNew);
    -
    -        LowererMD::EmitInt4Instr(instrNew);
    +        LowererMD::Legalize(instrNew);
     
             StackSym * stackSym = regOpnd->m_sym;
             Assert(!stackSym->m_isSingleDef);
    @@ -383,25 +527,19 @@ Security::EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue,
             *pNewOpnd = regOpnd;
     
             int32 value = (int32)constValue;
    -        value = value ^ cookie;
    +        value = value ^ cookieOpnd->AsInt32();
             return value;
         }
         else if (opnd->GetType() == TyUint32 || opnd->GetType() == TyUint16 || opnd->GetType() == TyUint8)
         {
    -        uint32 cookie = (uint32)Math::Rand();
    -        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(TyUint32, instr->m_func), TyUint32, instr->m_func);
    +        IR::RegOpnd *regOpnd = IR::RegOpnd::New(StackSym::New(opnd->GetType(), instr->m_func), opnd->GetType(), instr->m_func);
             IR::Instr * instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);
     
    -        IR::IntConstOpnd * cookieOpnd = IR::IntConstOpnd::New(cookie, TyUint32, instr->m_func);
    -
    -#if DBG_DUMP
    -        cookieOpnd->SetName(_u("cookie"));
    -#endif
    +        IR::IntConstOpnd * cookieOpnd = BuildCookieOpnd(opnd->GetType(), instr->m_func);
     
    -        instrNew = IR::Instr::New(Js::OpCode::Xor_I4, regOpnd, regOpnd, cookieOpnd, instr->m_func);
    +        instrNew = IR::Instr::New(LowererMD::MDXorOpcode, regOpnd, regOpnd, cookieOpnd, instr->m_func);
             instr->InsertBefore(instrNew);
    -
    -        LowererMD::EmitInt4Instr(instrNew);
    +        LowererMD::Legalize(instrNew);
     
             StackSym * stackSym = regOpnd->m_sym;
             Assert(!stackSym->m_isSingleDef);
    @@ -412,32 +550,33 @@ Security::EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue,
             *pNewOpnd = regOpnd;
     
             uint32 value = (uint32)constValue;
    -        value = value ^ cookie;
    +        value = value ^ cookieOpnd->AsUint32();
             return (IntConstType)value;
         }
         else
         {
    -#ifdef _M_X64
    +#if TARGET_64
             return this->EncodeAddress(instr, opnd, constValue, pNewOpnd);
     #else
             Assert(false);
    +        // (Prefast warning on failure to assign *pNewOpnd.)
    +        *pNewOpnd = nullptr;
             return 0;
     #endif
         }
     }
     
    -#ifdef _M_X64
    +#if TARGET_64
     size_t
    -Security::EncodeAddress(IR::Instr *instr, IR::Opnd *opnd, size_t value, IR::RegOpnd **pNewOpnd)
    +Security::EncodeAddress(IR::Instr * instr, IR::Opnd *opnd, size_t value, _Out_ IR::RegOpnd **pNewOpnd)
     {
         IR::Instr   *instrNew = nullptr;
    -    IR::RegOpnd *regOpnd  = IR::RegOpnd::New(TyMachReg, instr->m_func);
    +    IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyMachReg, instr->m_func);
     
         instrNew = LowererMD::CreateAssign(regOpnd, opnd, instr);
     
    -    size_t cookie = (size_t)Math::Rand();
    -    IR::IntConstOpnd *cookieOpnd = IR::IntConstOpnd::New(cookie, TyMachReg, instr->m_func);
    -    instrNew = IR::Instr::New(Js::OpCode::XOR, regOpnd, regOpnd, cookieOpnd, instr->m_func);
    +    IR::IntConstOpnd *cookieOpnd = BuildCookieOpnd(TyMachReg, instr->m_func);
    +    instrNew = IR::Instr::New(LowererMD::MDXorOpcode, regOpnd, regOpnd, cookieOpnd, instr->m_func);
         instr->InsertBefore(instrNew);
         LowererMD::Legalize(instrNew);
     
    @@ -448,6 +587,6 @@ Security::EncodeAddress(IR::Instr *instr, IR::Opnd *opnd, size_t value, IR::RegO
         stackSym->constantValue = value;
     
         *pNewOpnd = regOpnd;
    -    return value ^ cookie;
    +    return value ^ cookieOpnd->GetValue();
     }
     #endif
    
  • lib/Backend/Security.h+28 9 modified
    @@ -8,26 +8,45 @@ class Security
     {
     private:
         Func *func;
    +    IR::RegOpnd * basePlusCookieOpnd;
    +    IR::IntConstOpnd * cookieOpnd;
    +    IR::RegOpnd * baseOpnd;
     
     public:
    -    Security(Func * func) : func(func) {}
    +    Security(Func * func) : func(func), basePlusCookieOpnd(nullptr), cookieOpnd(nullptr), baseOpnd(nullptr) { }
     
         void            EncodeLargeConstants();
         void            InsertNOPs();
         static bool     DontEncode(IR::Opnd *opnd);
         static void     InsertRandomFunctionPad(IR::Instr * instrBeforeInstr);
     
     private:
    -    void            EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd);
    -    IntConstType    EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue, IR::RegOpnd ** pNewOpnd);
    -#ifdef _M_X64
    -    size_t          EncodeAddress(IR::Instr *instr, IR::Opnd *opnd, size_t value, IR::RegOpnd **pNewOpnd);
    +    bool            EncodeOpnd(IR::Instr *instr, IR::Opnd *opnd);
    +    uint            CalculateConstSize(IR::Opnd *opnd);
    +    IntConstType    EncodeValue(IR::Instr *instr, IR::Opnd *opnd, IntConstType constValue, _Out_ IR::RegOpnd ** pNewOpnd);
    +#if TARGET_64
    +    size_t          EncodeAddress(IR::Instr *instr, IR::Opnd *opnd, size_t value, _Out_ IR::RegOpnd **pNewOpnd);
     #endif
    +    static IR::IntConstOpnd * BuildCookieOpnd(IRType type, Func * func);
     
    -    // Large constants have more than 16 significant bits.
    -    // Constants except these are considered large: 0x0000????, 0xffff????, 0x????0000, 0x????ffff
    -    static bool     IsLargeConstant(int32 value) { return static_cast<int16>(value) != 0 && static_cast<int16>(value) != -1 && (value >> 16) != 0 && (value >> 16) != -1; }
    -    static bool     IsLargeConstant(int64 value) { return IsLargeConstant((int32)value) || IsLargeConstant((int32)(value >> 16)) || IsLargeConstant((int32)(value >> 32)); }
    +    template<typename T> static uint GetByteCount(T value)
    +    {
    +        uint byteCount = 0;
    +        for (uint i = 0; i < sizeof(T); ++i)
    +        {
    +            if (IsByteSet(value, i))
    +            {
    +                ++byteCount;
    +            }
    +        }
    +        return byteCount;
    +    }
    +
    +    template<typename T> static bool IsByteSet(T value, uint32 index)
    +    {
    +        const byte byteValue = (byte)(value >> (index * MachBits));
    +        return byteValue != 0 && byteValue != 0xFF;
    +    }
     
         void            InsertNOPBefore(IR::Instr *instr);
         int             GetNextNOPInsertPoint();
    
  • lib/Backend/ServerThreadContext.cpp+13 13 modified
    @@ -8,27 +8,26 @@
     #if ENABLE_OOP_NATIVE_CODEGEN
     #include "JITServer/JITServer.h"
     
    -ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data) :
    -    m_autoProcessHandle((HANDLE)data->processHandle),
    +ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data, HANDLE processHandle) :
    +    m_autoProcessHandle(processHandle),
         m_threadContextData(*data),
         m_refCount(0),
         m_numericPropertyBV(nullptr),
    -    m_preReservedSectionAllocator((HANDLE)data->processHandle),
    -    m_sectionAllocator((HANDLE)data->processHandle),
    -    m_thunkPageAllocators(nullptr, /* allocXData */ false, &m_sectionAllocator, nullptr, (HANDLE)data->processHandle),
    -    m_codePageAllocators(nullptr, ALLOC_XDATA, &m_sectionAllocator, &m_preReservedSectionAllocator, (HANDLE)data->processHandle),
    -    m_codeGenAlloc(nullptr, nullptr, &m_codePageAllocators, (HANDLE)data->processHandle),
    +    m_preReservedSectionAllocator(processHandle),
    +    m_sectionAllocator(processHandle),
    +    m_thunkPageAllocators(nullptr, /* allocXData */ false, &m_sectionAllocator, nullptr, processHandle),
    +    m_codePageAllocators(nullptr, ALLOC_XDATA, &m_sectionAllocator, &m_preReservedSectionAllocator, processHandle),
    +    m_codeGenAlloc(nullptr, nullptr, &m_codePageAllocators, processHandle),
     #if defined(_CONTROL_FLOW_GUARD) && (_M_IX86 || _M_X64)
    -    m_jitThunkEmitter(this, &m_sectionAllocator, (HANDLE)data->processHandle),
    +    m_jitThunkEmitter(this, &m_sectionAllocator, processHandle),
     #endif
         m_pageAlloc(nullptr, Js::Configuration::Global.flags, PageAllocatorType_BGJIT,
             AutoSystemInfo::Data.IsLowMemoryProcess() ?
             PageAllocator::DefaultLowMaxFreePageCount :
             PageAllocator::DefaultMaxFreePageCount
         )
     {
    -    ucrtC99MathApis.Ensure();
    -    m_pid = GetProcessId((HANDLE)data->processHandle);
    +    m_pid = GetProcessId(processHandle);
     
     #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
         m_codeGenAlloc.canCreatePreReservedSegment = data->allowPrereserveAlloc != FALSE;
    @@ -112,7 +111,7 @@ ServerThreadContext::IsThreadBound() const
     HANDLE
     ServerThreadContext::GetProcessHandle() const
     {
    -    return reinterpret_cast<HANDLE>(m_threadContextData.processHandle);
    +    return m_autoProcessHandle.GetHandle();
     }
     
     CustomHeap::OOPCodePageAllocators *
    @@ -159,10 +158,11 @@ ServerThreadContext::GetRuntimeCRTBaseAddress() const
         return static_cast<intptr_t>(m_threadContextData.crtBaseAddress);
     }
     
    +/* static */
     intptr_t
    -ServerThreadContext::GetJITCRTBaseAddress() const
    +ServerThreadContext::GetJITCRTBaseAddress()
     {
    -    return (intptr_t)ucrtC99MathApis.GetHandle();
    +    return (intptr_t)AutoSystemInfo::GetCRTHandle();
     }
     
     PageAllocator *
    
  • lib/Backend/ServerThreadContext.h+3 11 modified
    @@ -11,7 +11,7 @@ class ServerThreadContext : public ThreadContextInfo
     public:
         typedef BVSparseNode<JitArenaAllocator> BVSparseNode;
     
    -    ServerThreadContext(ThreadContextDataIDL * data);
    +    ServerThreadContext(ThreadContextDataIDL * data, HANDLE processHandle);
         ~ServerThreadContext();
     
         virtual HANDLE GetProcessHandle() const override;
    @@ -56,18 +56,10 @@ class ServerThreadContext : public ThreadContextInfo
     
         intptr_t GetRuntimeChakraBaseAddress() const;
         intptr_t GetRuntimeCRTBaseAddress() const;
    -    intptr_t GetJITCRTBaseAddress() const;
     
    -private:
    +    static intptr_t GetJITCRTBaseAddress();
     
    -    class AutoCloseHandle
    -    {
    -    public:
    -        AutoCloseHandle(HANDLE handle) : handle(handle) { Assert(handle != GetCurrentProcess()); }
    -        ~AutoCloseHandle() { CloseHandle(this->handle); }
    -    private:
    -        HANDLE handle;
    -    };
    +private:
     
         AutoCloseHandle m_autoProcessHandle;
     
    
  • lib/Common/Common/MathUtil.h+2 0 modified
    @@ -47,6 +47,8 @@ class Math
         static bool     FitsInDWord(size_t value) { return ((size_t)(signed int)(value & 0xFFFFFFFF) == value); }
         static bool     FitsInDWord(int64 value) { return ((int64)(signed int)(value & 0xFFFFFFFF) == value); }
     
    +    static bool     FitsInWord(int32 value) { return ((int32)(int16)(value & 0xFFFF) == value); }
    +
         static UINT_PTR Rand();
         static bool     IsPow2(int32 val) { return (val > 0 && ((val-1) & val) == 0); }
         static uint32   NextPowerOf2(uint32 n);
    
  • lib/Common/ConfigFlagsList.h+4 2 modified
    @@ -609,7 +609,8 @@ PHASE(All)
     #define DEFAULT_CONFIG_EnumerateSpecialPropertiesInDebugger (true)
     #endif
     
    -#define DEFAULT_CONFIG_MaxJITFunctionBytecodeSize (120000)
    +#define DEFAULT_CONFIG_MaxJITFunctionBytecodeByteLength (4800000)
    +#define DEFAULT_CONFIG_MaxJITFunctionBytecodeCount (120000)
     
     #define DEFAULT_CONFIG_JitQueueThreshold      (6)
     
    @@ -1243,7 +1244,8 @@ FLAGR(Number,   MinDeferredFuncTokenCount, "Minimum length in tokens of defer-pa
     #if DBG
     FLAGNR(Number,  SkipFuncCountForBailOnNoProfile,  "Initial Number of functions in a func body to be skipped from forcibly inserting BailOnNoProfile.", DEFAULT_CONFIG_SkipFuncCountForBailOnNoProfile)
     #endif
    -FLAGNR(Number,  MaxJITFunctionBytecodeSize, "The biggest function we'll JIT (bytecode size)", DEFAULT_CONFIG_MaxJITFunctionBytecodeSize)
    +FLAGNR(Number, MaxJITFunctionBytecodeByteLength, "The biggest function we'll JIT (bytecode bytelength)", DEFAULT_CONFIG_MaxJITFunctionBytecodeByteLength)
    +FLAGNR(Number, MaxJITFunctionBytecodeCount, "The biggest function we'll JIT (bytecode count)", DEFAULT_CONFIG_MaxJITFunctionBytecodeCount)
     FLAGNR(Number,  MaxLoopsPerFunction   , "Maximum number of loops in any function in the script", DEFAULT_CONFIG_MaxLoopsPerFunction)
     FLAGNR(Number,  FuncObjectInlineCacheThreshold  , "Maximum number of inline caches a function body may have to allow for inline caches to be allocated on the function object", DEFAULT_CONFIG_FuncObjectInlineCacheThreshold)
     FLAGNR(Boolean, NoDeferParse          , "Disable deferred parsing", false)
    
  • lib/Common/Core/SysInfo.cpp+5 0 modified
    @@ -397,6 +397,11 @@ LPCWSTR AutoSystemInfo::GetJscriptDllFileName()
         return (LPCWSTR)Data.binaryName;
     }
     
    +HMODULE AutoSystemInfo::GetCRTHandle()
    +{
    +    return GetModuleHandle(_u("msvcrt.dll"));
    +}
    +
     bool AutoSystemInfo::IsLowMemoryProcess()
     {
         ULONG64 commit = ULONG64(-1);
    
  • lib/Common/Core/SysInfo.h+1 0 modified
    @@ -49,6 +49,7 @@ class AutoSystemInfo : public SYSTEM_INFO
         static DWORD SaveModuleFileName(HANDLE hMod);
         static LPCWSTR GetJscriptDllFileName();
         static HRESULT GetJscriptFileVersion(DWORD* majorVersion, DWORD* minorVersion, DWORD *buildDateHash = nullptr, DWORD *buildTimeHash = nullptr);
    +    static HMODULE GetCRTHandle();
     #if DBG
         static bool IsInitialized();
     #endif
    
  • lib/JITClient/JITManager.cpp+12 24 modified
    @@ -31,7 +31,6 @@ JITManager::JITManager() :
         m_oopJitEnabled(false),
         m_isJITServer(false),
         m_failingHRESULT(S_OK),
    -    m_serverHandle(nullptr),
         m_jitConnectionId()
     {
     }
    @@ -42,10 +41,6 @@ JITManager::~JITManager()
         {
             RpcBindingFree(&m_rpcBindingHandle);
         }
    -    if (m_serverHandle)
    -    {
    -        CloseHandle(m_serverHandle);
    -    }
     }
     
     /* static */
    @@ -187,12 +182,6 @@ JITManager::IsConnected() const
         return m_rpcBindingHandle != nullptr && !HasJITFailed();
     }
     
    -HANDLE
    -JITManager::GetServerHandle() const
    -{
    -    return m_serverHandle;
    -}
    -
     void
     JITManager::EnableOOPJIT()
     {
    @@ -230,7 +219,6 @@ JITManager::ConnectRpcServer(__in HANDLE jitProcessHandle, __in_opt void* server
     {
         Assert(IsOOPJITEnabled());
         Assert(m_rpcBindingHandle == nullptr);
    -    Assert(m_serverHandle == nullptr);
     
         HRESULT hr = E_FAIL;
     
    @@ -240,12 +228,6 @@ JITManager::ConnectRpcServer(__in HANDLE jitProcessHandle, __in_opt void* server
             return E_FAIL;
         }
     
    -    if (!DuplicateHandle(GetCurrentProcess(), jitProcessHandle, GetCurrentProcess(), &m_serverHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
    -    {
    -        hr = HRESULT_FROM_WIN32(GetLastError());
    -        goto FailureCleanup;
    -    }
    -
         hr = CreateBinding(jitProcessHandle, serverSecurityDescriptor, &connectionUuid, &m_rpcBindingHandle);
         if (FAILED(hr))
         {
    @@ -257,11 +239,6 @@ JITManager::ConnectRpcServer(__in HANDLE jitProcessHandle, __in_opt void* server
         return hr;
     
     FailureCleanup:
    -    if (m_serverHandle)
    -    {
    -        CloseHandle(m_serverHandle);
    -        m_serverHandle = nullptr;
    -    }
         if (m_rpcBindingHandle)
         {
             RpcBindingFree(&m_rpcBindingHandle);
    @@ -298,6 +275,9 @@ JITManager::Shutdown()
     HRESULT
     JITManager::InitializeThreadContext(
         __in ThreadContextDataIDL * data,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +    __in HANDLE processHandle,
    +#endif
         __out PPTHREADCONTEXT_HANDLE threadContextInfoAddress,
         __out intptr_t * prereservedRegionAddr,
         __out intptr_t * jitThunkAddr)
    @@ -307,7 +287,15 @@ JITManager::InitializeThreadContext(
         HRESULT hr = E_FAIL;
         RpcTryExcept
         {
    -        hr = ClientInitializeThreadContext(m_rpcBindingHandle, data, threadContextInfoAddress, prereservedRegionAddr, jitThunkAddr);
    +        hr = ClientInitializeThreadContext(
    +            m_rpcBindingHandle,
    +            data,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +            processHandle,
    +#endif
    +            threadContextInfoAddress,
    +            prereservedRegionAddr,
    +            jitThunkAddr);
         }
         RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
         {
    
  • lib/JITClient/JITManager.h+6 8 modified
    @@ -31,10 +31,11 @@ class JITManager
         void SetJITFailed(HRESULT hr);
         bool HasJITFailed() const;
     
    -    HANDLE GetServerHandle() const;
    -
         HRESULT InitializeThreadContext(
             __in ThreadContextDataIDL * data,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +        __in HANDLE processHandle,
    +#endif
             __out PPTHREADCONTEXT_HANDLE threadContextInfoAddress,
             __out intptr_t * prereservedRegionAddr,
             __out intptr_t * jitThunkAddr);
    @@ -123,7 +124,6 @@ class JITManager
             __out RPC_BINDING_HANDLE* bindingHandle);
     
         RPC_BINDING_HANDLE m_rpcBindingHandle;
    -    HANDLE m_serverHandle;
         UUID m_jitConnectionId;
         bool m_oopJitEnabled;
         bool m_isJITServer;
    @@ -147,13 +147,11 @@ class JITManager
         void EnableOOPJIT() { Assert(false); }
         void SetJITFailed(HRESULT hr) { Assert(false); }
     
    -    HANDLE GetServerHandle() const
    -    {
    -        Assert(false); return HANDLE();
    -    }
    -
         HRESULT InitializeThreadContext(
             __in ThreadContextDataIDL * data,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +        __in HANDLE processHandle,
    +#endif
             __out PPTHREADCONTEXT_HANDLE threadContextInfoAddress,
             __out intptr_t *prereservedRegionAddr,
             __out intptr_t * jitThunkAddr)
    
  • lib/JITIDL/ChakraJIT.idl+10 0 modified
    @@ -8,6 +8,13 @@ cpp_quote("#define __JITTypes_h__")
     
     #include "JITTypes.h"
     
    +// we can't include Windows.h, so for simplicity, let's define these values ourself
    +// from: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880.aspx
    +#define PROCESS_VM_OPERATION 0x0008
    +#define PROCESS_VM_READ 0x0010
    +#define PROCESS_VM_WRITE 0x0020
    +#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
    +
     cpp_quote("#endif //__JITTypes_h__")
     
     [
    @@ -21,6 +28,9 @@ interface IChakraJIT
         HRESULT InitializeThreadContext(
             [in] handle_t binding,
             [in] ThreadContextDataIDL * threadData,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +        [in, system_handle(sh_process, PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_LIMITED_INFORMATION)] HANDLE processHandle,
    +#endif
             [out] PPTHREADCONTEXT_HANDLE threadContextInfoAddress,
             [out] CHAKRA_PTR * prereservedRegionAddr,
             [out] CHAKRA_PTR * jitThunkAddr);
    
  • lib/JITIDL/JITTypes.h+8 1 modified
    @@ -7,6 +7,14 @@
     
     #ifdef __midl
     import "wtypes.idl";
    +#include "sdkddkver.h"
    +#endif
    +
    +#if defined(WINVER) && WINVER >= _WIN32_WINNT_WINBLUE // on 8.1+, RPC can marshal process handle for us
    +#ifdef __midl
    +cpp_quote("#define USE_RPC_HANDLE_MARSHALLING 1")
    +#endif
    +#define USE_RPC_HANDLE_MARSHALLING 1
     #endif
     
     #if defined(_M_IX86) || defined(_M_ARM)
    @@ -302,7 +310,6 @@ typedef struct ThreadContextDataIDL
     
         IDL_PAD2(0)
         X64_PAD4(1)
    -    CHAKRA_PTR processHandle;
         CHAKRA_PTR chakraBaseAddress;
         CHAKRA_PTR crtBaseAddress;
         CHAKRA_PTR threadStackLimitAddr;
    
  • lib/JITServer/JITServer.cpp+30 19 modified
    @@ -193,6 +193,9 @@ HRESULT
     ServerInitializeThreadContext(
         /* [in] */ handle_t binding,
         /* [in] */ __RPC__in ThreadContextDataIDL * threadContextData,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +    /* [in] */ __RPC__in HANDLE processHandle,
    +#endif
         /* [out] */ __RPC__deref_out_opt PPTHREADCONTEXT_HANDLE threadContextInfoAddress,
         /* [out] */ __RPC__out intptr_t *prereservedRegionAddr,
         /* [out] */ __RPC__out intptr_t *jitThunkAddr)
    @@ -208,45 +211,53 @@ ServerInitializeThreadContext(
         *jitThunkAddr = 0;
     
         ServerThreadContext * contextInfo = nullptr;
    +
    +    DWORD clientPid;
    +    HRESULT hr = HRESULT_FROM_WIN32(I_RpcBindingInqLocalClientPID(binding, &clientPid));
    +    if (FAILED(hr))
    +    {
    +        return hr;
    +    }
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +    HANDLE targetHandle;
    +    if (!DuplicateHandle(GetCurrentProcess(), processHandle, GetCurrentProcess(), &targetHandle, 0, false, DUPLICATE_SAME_ACCESS))
    +    {
    +        return E_ACCESSDENIED;
    +    }
    +#else
    +    HANDLE targetHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_LIMITED_INFORMATION, false, clientPid);
    +    if (!targetHandle)
    +    {
    +        return E_ACCESSDENIED;
    +    }
    +#endif
         try
         {
             AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory));
    -        contextInfo = HeapNew(ServerThreadContext, threadContextData);
    +        contextInfo = HeapNew(ServerThreadContext, threadContextData, targetHandle);
             ServerContextManager::RegisterThreadContext(contextInfo);
         }
         catch (Js::OutOfMemoryException)
         {
    -        CloseHandle((HANDLE)threadContextData->processHandle);
    +        CloseHandle(targetHandle);
             return E_OUTOFMEMORY;
         }
     
         return ServerCallWrapper(contextInfo, [&]()->HRESULT
         {
    -        RPC_CALL_ATTRIBUTES CallAttributes = { 0 };
    -
    -        CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
    -        CallAttributes.Flags = RPC_QUERY_CLIENT_PID;
    -        HRESULT hr = HRESULT_FROM_WIN32(RpcServerInqCallAttributes(binding, &CallAttributes));
    -        if (FAILED(hr))
    -        {
    -            return hr;
    -        }
    -        if (CallAttributes.ClientPID != (HANDLE)contextInfo->GetRuntimePid())
    +        if (clientPid != contextInfo->GetRuntimePid())
             {
                 return E_ACCESSDENIED;
             }
    -        hr = CheckModuleAddress(contextInfo->GetProcessHandle(), (LPCVOID)contextInfo->GetRuntimeChakraBaseAddress(), (LPCVOID)AutoSystemInfo::Data.dllLoadAddress);
    +        hr = CheckModuleAddress(targetHandle, (LPCVOID)contextInfo->GetRuntimeChakraBaseAddress(), (LPCVOID)AutoSystemInfo::Data.dllLoadAddress);
             if (FAILED(hr))
             {
                 return hr;
             }
    -        if (contextInfo->GetUCrtC99MathApis()->IsAvailable())
    +        hr = CheckModuleAddress(targetHandle, (LPCVOID)contextInfo->GetRuntimeCRTBaseAddress(), (LPCVOID)contextInfo->GetJITCRTBaseAddress());
    +        if (FAILED(hr))
             {
    -            hr = CheckModuleAddress(contextInfo->GetProcessHandle(), (LPCVOID)contextInfo->GetRuntimeCRTBaseAddress(), (LPCVOID)contextInfo->GetJITCRTBaseAddress());
    -            if (FAILED(hr))
    -            {
    -                return hr;
    -            }
    +            return hr;
             }
     
             *threadContextInfoAddress = (PTHREADCONTEXT_HANDLE)EncodePointer(contextInfo);
    
  • lib/Parser/Parse.cpp+20 8 modified
    @@ -3802,9 +3802,10 @@ ParseNodePtr Parser::ParseArgList( bool *pCallOfConstants, uint16 *pSpreadArgCou
         int count=0;
         while (true)
         {
    -        // the count of arguments has to fit in an unsigned short
    -        if (count > 0xffffU)
    +        if (count >= Js::Constants::MaxAllowedArgs)
    +        {
                 Error(ERRnoMemory);
    +        }
             // Allow spread in argument lists.
             IdentToken token;
             pnodeArg = ParseExpr<buildAST>(koplCma, nullptr, TRUE, /* fAllowEllipsis */TRUE, NULL, nullptr, nullptr, &token);
    @@ -5164,7 +5165,18 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
                 {
                     m_reparsingLambdaParams = true;
                 }
    +            DeferredFunctionStub *saveDeferredStub = nullptr;
    +            if (buildAST)
    +            {
    +                // Don't try to make use of stubs while parsing formals. Issues with arrow functions, nested functions.
    +                saveDeferredStub = m_currDeferredStub;
    +                m_currDeferredStub = nullptr;
    +            }
                 this->ParseFncFormals<buildAST>(pnodeFnc, pnodeFncParent, flags);
    +            if (buildAST)
    +            {
    +                m_currDeferredStub = saveDeferredStub;
    +            }
                 m_reparsingLambdaParams = fLambdaParamsSave;
             }
     
    @@ -6300,9 +6312,9 @@ void Parser::ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc,
                             Assert(lexNode->IsVarLetOrConst());
                             UpdateOrCheckForDuplicateInFormals(lexNode->sxVar.pid, &formals);
                             lexNode->sxVar.sym->SetSymbolType(STFormal);
    -                        if (m_currentNodeFunc != nullptr && lexNode->sxVar.pid == wellKnownPropertyPids.arguments)
    +                        if (lexNode->sxVar.pid == wellKnownPropertyPids.arguments)
                             {
    -                            m_currentNodeFunc->grfpn |= PNodeFlags::fpnArguments_overriddenInParam;
    +                            GetCurrentFunctionNode()->grfpn |= PNodeFlags::fpnArguments_overriddenInParam;
                             }
                         }
     
    @@ -7577,7 +7589,7 @@ ParseNodePtr Parser::ParseStringTemplateDecl(ParseNodePtr pnodeTagFnc)
     
             // We are not able to pass more than a ushort worth of arguments to the tag
             // so use that as a logical limit on the number of string constant pieces.
    -        if (stringConstantCount >= USHRT_MAX)
    +        if (stringConstantCount >= Js::Constants::MaxAllowedArgs)
             {
                 Error(ERRnoMemory);
             }
    @@ -8842,19 +8854,19 @@ ParseNodePtr Parser::ParseVariableDeclaration(
                     CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(Let, m_scriptContext);
                 }
     
    -            if (pid == wellKnownPropertyPids.arguments && m_currentNodeFunc)
    +            if (pid == wellKnownPropertyPids.arguments)
                 {
                     // This var declaration may change the way an 'arguments' identifier in the function is resolved
                     if (declarationType == tkVAR)
                     {
    -                    m_currentNodeFunc->grfpn |= PNodeFlags::fpnArguments_varDeclaration;
    +                    GetCurrentFunctionNode()->grfpn |= PNodeFlags::fpnArguments_varDeclaration;
                     }
                     else
                     {
                         if (GetCurrentBlockInfo()->pnodeBlock->sxBlock.blockType == Function)
                         {
                             // Only override arguments if we are at the function block level.
    -                        m_currentNodeFunc->grfpn |= PNodeFlags::fpnArguments_overriddenByDecl;
    +                        GetCurrentFunctionNode()->grfpn |= PNodeFlags::fpnArguments_overriddenByDecl;
                         }
                     }
                 }
    
  • lib/Parser/ptree.h+12 0 modified
    @@ -368,6 +368,18 @@ struct PnFnc
         bool CanBeDeferred() const { return canBeDeferred; }
         bool IsBodyAndParamScopeMerged() { return isBodyAndParamScopeMerged; }
         bool FIBPreventsDeferral() const { return fibPreventsDeferral; }
    +    // Only allow the normal functions to be asm.js
    +    bool IsAsmJsAllowed() const { return (fncFlags & ~(
    +        kFunctionAsmjsMode |
    +        kFunctionNested |
    +        kFunctionDeclaration |
    +        kFunctionStrictMode |
    +        kFunctionNameIsHidden |
    +        kFunctionHasReferenceableBuiltInArguments |
    +        kFunctionHasNonThisStmt |
    +        // todo:: we shouldn't accept kFunctionHasAnyWriteToFormals on the asm module, but it looks like a bug is setting that flag incorrectly
    +        kFunctionHasAnyWriteToFormals
    +    )) == 0; }
     
         size_t LengthInBytes()
         {
    
  • lib/Runtime/Base/Constants.h+5 2 modified
    @@ -45,8 +45,11 @@ namespace Js
             static const InlineCacheIndex   NoInlineCacheIndex          = (InlineCacheIndex)-1;
             static const uint               UninitializedValue          = (uint)-1;
             static const ArgSlot            InvalidArgSlot              = (ArgSlot)-1;
    -        static const uint32             InvalidSymID = (uint32)-1;
    -        static const size_t             InvalidSignature = (size_t)-1;
    +        static const uint32             InvalidSymID                = (uint32)-1;
    +        static const size_t             InvalidSignature            = (size_t)-1;
    +
    +        // We add extra args during bytecode phase, so account for those and few extra slots for padding.
    +        static const uint16             MaxAllowedArgs              = UShortMaxValue - 6;
     
             static const uint64 ExponentMask;
             static const uint64 MantissaMask;
    
  • lib/Runtime/Base/FunctionBody.cpp+17 21 modified
    @@ -948,6 +948,23 @@ namespace Js
                 Js::ParseableFunctionInfo::NewDeferredFunctionFromFunctionBody(this);
             FunctionInfo * functionInfo = this->GetFunctionInfo();
     
    +        this->RedeferFunctionObjectTypes();
    +
    +        this->Cleanup(false);
    +        if (GetIsFuncRegistered())
    +        {
    +            this->GetUtf8SourceInfo()->RemoveFunctionBody(this);
    +        }
    +
    +        // New allocation is done at this point, so update existing structures
    +        // Adjust functionInfo attributes, point to new proxy
    +        functionInfo->SetAttributes((FunctionInfo::Attributes)(functionInfo->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
    +        functionInfo->SetFunctionProxy(parseableFunctionInfo);
    +        functionInfo->SetOriginalEntryPoint(DefaultEntryThunk);
    +    }
    +
    +    void FunctionBody::RedeferFunctionObjectTypes()
    +    {
             this->MapFunctionObjectTypes([&](ScriptFunctionType* functionType)
             {
                 Assert(functionType->GetTypeId() == TypeIds_Function);
    @@ -961,18 +978,6 @@ namespace Js
                     functionType->GetEntryPointInfo()->jsMethod = GetScriptContext()->DeferredParsingThunk;
                 }
             });
    -
    -        this->Cleanup(false);
    -        if (GetIsFuncRegistered())
    -        {
    -            this->GetUtf8SourceInfo()->RemoveFunctionBody(this);
    -        }
    -
    -        // New allocation is done at this point, so update existing structures
    -        // Adjust functionInfo attributes, point to new proxy
    -        functionInfo->SetAttributes((FunctionInfo::Attributes)(functionInfo->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
    -        functionInfo->SetFunctionProxy(parseableFunctionInfo);
    -        functionInfo->SetOriginalEntryPoint(DefaultEntryThunk);
         }
     
         void FunctionBody::SetDefaultFunctionEntryPointInfo(FunctionEntryPointInfo* entryPointInfo, const JavascriptMethod originalEntryPoint)
    @@ -1923,15 +1928,6 @@ namespace Js
     
             FunctionInfoArray nested = this->GetNestedFuncArray();
             nested[index] = nestedFunc;
    -
    -        if (nestedFunc)
    -        {
    -            if (!this->GetSourceContextInfo()->IsDynamic() && nestedFunc->IsDeferredParseFunction() && nestedFunc->GetParseableFunctionInfo()->GetIsDeclaration() && this->GetIsTopLevel() && !(flags & fscrEvalCode))
    -            {
    -                this->GetUtf8SourceInfo()->TrackDeferredFunction(nestedFunc->GetLocalFunctionId(), nestedFunc->GetParseableFunctionInfo());
    -            }
    -        }
    -
         }
     
         FunctionInfo* ParseableFunctionInfo::GetNestedFunc(uint index)
    
  • lib/Runtime/Base/FunctionBody.h+3 0 modified
    @@ -2641,6 +2641,7 @@ namespace Js
     
             bool DoRedeferFunction(uint inactiveThreshold) const;
             void RedeferFunction();
    +        void RedeferFunctionObjectTypes();
             bool IsActiveFunction(ActiveFunctionSet * pActiveFuncs) const;
             bool TestAndUpdateActiveFunctions(ActiveFunctionSet * pActiveFuncs) const;
             void UpdateActiveFunctionSet(ActiveFunctionSet * pActiveFuncs, FunctionCodeGenRuntimeData *callSiteData) const;
    @@ -3729,6 +3730,8 @@ namespace Js
                 if (this->pfi != nullptr && this->pfi->GetFunctionInfo()->GetFunctionProxy() != this->pfi)
                 {
                     FunctionInfo *functionInfo = this->pfi->GetFunctionInfo();
    +                FunctionBody *functionBody = functionInfo->GetFunctionProxy()->GetFunctionBody();
    +                functionBody->RedeferFunctionObjectTypes();
                     functionInfo->SetAttributes(
                         (FunctionInfo::Attributes)(functionInfo->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
                     functionInfo->SetFunctionProxy(this->pfi);
    
  • lib/Runtime/Base/ThreadContext.cpp+15 10 modified
    @@ -1976,20 +1976,18 @@ ThreadContext::EnsureJITThreadContext(bool allowPrereserveAlloc)
             return true;
         }
     
    -    ThreadContextDataIDL contextData;
    -    HANDLE serverHandle = JITManager::GetJITManager()->GetServerHandle();
    -
    -    HANDLE jitTargetHandle = nullptr;
    -    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), serverHandle, &jitTargetHandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +    HANDLE processHandle;
    +    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &processHandle, 0, false, DUPLICATE_SAME_ACCESS))
         {
             return false;
         }
    +    AutoCloseHandle autoClose(processHandle);
    +#endif
     
    -    contextData.processHandle = (intptr_t)jitTargetHandle;
    -
    +    ThreadContextDataIDL contextData;
         contextData.chakraBaseAddress = (intptr_t)AutoSystemInfo::Data.GetChakraBaseAddr();
    -    ucrtC99MathApis.Ensure();
    -    contextData.crtBaseAddress = (intptr_t)ucrtC99MathApis.GetHandle();
    +    contextData.crtBaseAddress = (intptr_t)AutoSystemInfo::GetCRTHandle();
         contextData.threadStackLimitAddr = reinterpret_cast<intptr_t>(GetAddressOfStackLimitForCurrentThread());
         contextData.bailOutRegisterSaveSpaceAddr = (intptr_t)bailOutRegisterSaveSpace;
         contextData.disableImplicitFlagsAddr = (intptr_t)GetAddressOfDisableImplicitFlags();
    @@ -2012,7 +2010,14 @@ ThreadContext::EnsureJITThreadContext(bool allowPrereserveAlloc)
             }
         }
     
    -    HRESULT hr = JITManager::GetJITManager()->InitializeThreadContext(&contextData, &m_remoteThreadContextInfo, &m_prereservedRegionAddr, &m_jitThunkStartAddr);
    +    HRESULT hr = JITManager::GetJITManager()->InitializeThreadContext(
    +        &contextData,
    +#ifdef USE_RPC_HANDLE_MARSHALLING
    +        processHandle,
    +#endif
    +        &m_remoteThreadContextInfo,
    +        &m_prereservedRegionAddr,
    +        &m_jitThunkStartAddr);
         JITManager::HandleServerCallResult(hr, RemoteCallType::StateUpdate);
     
         return m_remoteThreadContextInfo != nullptr;
    
  • lib/Runtime/Base/ThreadContext.h+4 0 modified
    @@ -822,6 +822,8 @@ class ThreadContext sealed :
     
         NativeLibraryEntryRecord nativeLibraryEntry;
     
    +    UCrtC99MathApis ucrtC99MathApis;
    +
         // Indicates the current loop depth as observed by the interpreter. The interpreter causes this value to be updated upon
         // entering and leaving a loop.
         uint8 loopDepth;
    @@ -859,6 +861,8 @@ class ThreadContext sealed :
     
         CriticalSection* GetFunctionBodyLock() { return &csFunctionBody; }
     
    +    UCrtC99MathApis* GetUCrtC99MathApis() { return &ucrtC99MathApis; }
    +
         Js::IsConcatSpreadableCache* GetIsConcatSpreadableCache() { return &isConcatSpreadableCache; }
     
     #ifdef ENABLE_GLOBALIZATION
    
  • lib/Runtime/Base/ThreadContextInfo.cpp+1 1 modified
    @@ -395,7 +395,7 @@ ThreadContextInfo::IsCFGEnabled()
         PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY CfgPolicy;
         m_delayLoadWinCoreProcessThreads.EnsureFromSystemDirOnly();
         BOOL isGetMitigationPolicySucceeded = m_delayLoadWinCoreProcessThreads.GetMitigationPolicyForProcess(
    -        this->GetProcessHandle(),
    +        GetCurrentProcess(),
             ProcessControlFlowGuardPolicy,
             &CfgPolicy,
             sizeof(CfgPolicy));
    
  • lib/Runtime/Base/ThreadContextInfo.h+9 3 modified
    @@ -121,10 +121,16 @@ class ThreadContextInfo
         Js::DelayLoadWinCoreProcessThreads m_delayLoadWinCoreProcessThreads;
     #endif
     
    -    UCrtC99MathApis* GetUCrtC99MathApis() { return &ucrtC99MathApis; }
     protected:
    -
    -    UCrtC99MathApis ucrtC99MathApis;
    +    class AutoCloseHandle
    +    {
    +    public:
    +        AutoCloseHandle(HANDLE handle) : handle(handle) { Assert(this->handle != GetCurrentProcess()); }
    +        ~AutoCloseHandle() { CloseHandle(this->handle); }
    +        HANDLE GetHandle() const { return this->handle; }
    +    private:
    +        HANDLE handle;
    +    };
     
         Js::TypeId wellKnownHostTypeIds[WellKnownHostType_Last + 1];
     
    
  • lib/Runtime/ByteCode/ByteCodeEmitter.cpp+19 14 modified
    @@ -3595,6 +3595,19 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode)
         }
     #endif
     
    +    if (!byteCodeFunction->GetSourceContextInfo()->IsDynamic() && byteCodeFunction->GetIsTopLevel() && !(this->flags & fscrEvalCode))
    +    {
    +        // Add the top level of nested functions to the tracking dictionary. Wait until this point so that all nested functions have gone
    +        // through the Emit API so source info, etc., is initialized, and these are not orphaned functions left behind by an unfinished pass.
    +        byteCodeFunction->ForEachNestedFunc([&](Js::FunctionProxy * nestedFunc, uint32 i)
    +        {
    +            if (nestedFunc && nestedFunc->IsDeferredParseFunction() && nestedFunc->GetParseableFunctionInfo()->GetIsDeclaration())
    +            {
    +                byteCodeFunction->GetUtf8SourceInfo()->TrackDeferredFunction(nestedFunc->GetLocalFunctionId(), nestedFunc->GetParseableFunctionInfo());
    +            }
    +            return true;
    +        });
    +    }
     
         byteCodeFunction->SetInitialDefaultEntryPoint();
         byteCodeFunction->SetCompileCount(UInt32Math::Add(byteCodeFunction->GetCompileCount(), 1));
    @@ -6132,6 +6145,8 @@ unsigned int CountArguments(ParseNode *pnode, BOOL *pSideEffect = nullptr)
             }
         }
     
    +    AssertOrFailFastMsg(argCount < Js::Constants::UShortMaxValue, "Number of allowed arguments are already capped at parser level");
    +
         return argCount;
     }
     
    @@ -7353,15 +7368,10 @@ Js::ArgSlot EmitArgListEnd(
         BOOL fIsEval = (evalLocation != Js::Constants::NoRegister);
         BOOL fHasNewTarget = (newTargetLocation != Js::Constants::NoRegister);
     
    -    Js::ArgSlot argSlotIndex = (Js::ArgSlot) argIndex;
    -    static const Js::ArgSlot maxExtraArgSlot = 4;  // max(extraEvalArg, extraArg), where extraEvalArg==2 (moduleRoot,env), extraArg==4 (this, eval, evalInModule, newTarget)
    -
    -    // check for integer overflow with margin for increments below to calculate argument count
    -    if ((size_t)argSlotIndex != argIndex || argSlotIndex + maxExtraArgSlot < argSlotIndex)
    -    {
    -        Js::Throw::OutOfMemory();
    -    }
    +    static const size_t maxExtraArgSlot = 4;  // max(extraEvalArg, extraArg), where extraEvalArg==2 (moduleRoot,env), extraArg==4 (this, eval, evalInModule, newTarget)
    +    AssertOrFailFastMsg(argIndex < Js::Constants::UShortMaxValue - maxExtraArgSlot, "Number of allowed arguments are already capped at parser level");
     
    +    Js::ArgSlot argSlotIndex = (Js::ArgSlot) argIndex;
         Js::ArgSlot evalIndex;
     
         if (fIsPut)
    @@ -8208,12 +8218,7 @@ void EmitNew(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* f
     
         BOOL fSideEffectArgs = FALSE;
         unsigned int tmpCount = CountArguments(pnode->sxCall.pnodeArgs, &fSideEffectArgs);
    -    Assert(argCount == tmpCount);
    -
    -    if (argCount != (Js::ArgSlot)argCount)
    -    {
    -        Js::Throw::OutOfMemory();
    -    }
    +    AssertOrFailFastMsg(argCount == tmpCount, "argCount cannot overflow as max args capped at parser level");
     
         byteCodeGenerator->StartStatement(pnode);
     
    
  • lib/Runtime/ByteCode/ByteCodeGenerator.cpp+10 0 modified
    @@ -3688,6 +3688,8 @@ void PreVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
                         item->sxVar.pid->Psz(), sym->GetSymbolTypeName());
                 }
     #endif
    +            sym->SetIsCatch(true);
    +            sym->SetIsBlockVar(true);
             });
         }
         else
    @@ -5258,6 +5260,14 @@ void AssignRegisters(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
     #endif
                         auto symName = sym->GetName();
                         sym = funcInfo->bodyScope->FindLocalSymbol(symName);
    +
    +                    if (sym == nullptr && nop == knopLetDecl && pnode->sxVar.sym->GetIsCatch())
    +                    {
    +                        // This should be  a scenario like try {} catch([x]) {} with no duplicate definition inside the catch block.
    +                        // In non-destructured catch block param case, the created node will be a name node, not a var node.
    +                        break;
    +                    }
    +
                         if (sym == nullptr)
                         {
                             sym = funcInfo->paramScope->FindLocalSymbol(symName);
    
  • lib/Runtime/Language/AsmJs.cpp+7 2 modified
    @@ -62,7 +62,7 @@ namespace Js
     
             if (fnc.HasNonSimpleParameterList())
             {
    -            return m.Fail(fn, _u("default & rest args not allowed"));
    +            return m.Fail(fn, _u("default, rest & destructuring args not allowed"));
             }
     
             if (fnc.IsStaticMember())
    @@ -90,6 +90,11 @@ namespace Js
                 return m.Fail(fn, _u("closure functions are not allowed"));
             }
     
    +        if (!fnc.IsAsmJsAllowed())
    +        {
    +            return m.Fail(fn, _u("invalid function flags detected"));
    +        }
    +
             return true;
         }
     
    @@ -765,7 +770,7 @@ namespace Js
                     }
                     else if (decl->nop != knopConstDecl && decl->nop != knopVarDecl)
                     {
    -                    break;
    +                    goto varDeclEnd;
                     }
     
                     if (decl->sxVar.pnodeInit && decl->sxVar.pnodeInit->nop == knopArray)
    
  • lib/Runtime/Language/InterpreterStackFrame.cpp+2 1 modified
    @@ -2936,7 +2936,8 @@ namespace Js
             newInstance->m_reader.Create(funcObj->GetFunctionBody());
             // now that we have set up the new frame, let's interpret it!
             funcObj->GetFunctionBody()->BeginExecution();
    -        PushPopFrameHelper(newInstance, _ReturnAddress(), _AddressOfReturnAddress());
    +
    +        PushPopFrameHelper pushPopFrameHelper(newInstance, this->returnAddress, this->addressOfReturnAddress);
             Var retVal = newInstance->ProcessUnprofiled();
     
             if (doProfile)
    
  • lib/Runtime/Language/JavascriptExceptionOperators.cpp+1 1 modified
    @@ -970,7 +970,7 @@ namespace Js
         // We might be trying to raise a stack overflow exception from the interpreter before
         // we've executed code in the current script stack frame. In that case the current byte
         // code offset is 0. In such cases walk to the caller's caller.
    -    BOOL JavascriptExceptionOperators::GetCaller(JavascriptStackWalker& walker, JavascriptFunction*& jsFunc)
    +    BOOL JavascriptExceptionOperators::GetCaller(JavascriptStackWalker& walker, _Out_opt_ JavascriptFunction*& jsFunc)
         {
             if (! walker.GetCaller(&jsFunc))
             {
    
  • lib/Runtime/Language/JavascriptExceptionOperators.h+1 1 modified
    @@ -97,7 +97,7 @@ namespace Js
                 uint64 stackCrawlLimit, PVOID returnAddress, bool isThrownException, bool resetStack = false);
     
             static void ThrowExceptionObjectInternal(Js::JavascriptExceptionObject * exceptionObject, ScriptContext* scriptContext, bool fillExceptionContext, bool considerPassingToDebugger, PVOID returnAddress, bool resetStack);
    -        static BOOL GetCaller(JavascriptStackWalker& walker, JavascriptFunction*& jsFunc);
    +        static BOOL GetCaller(JavascriptStackWalker& walker, _Out_opt_ JavascriptFunction*& jsFunc);
             static void DumpStackTrace(JavascriptExceptionContext& exceptionContext, bool isThrownException = true);
             static JavascriptExceptionContext::StackTrace* TrimStackTraceForThrownObject(JavascriptExceptionContext::StackTrace* stackTraceOriginal, Var thrownObject, ScriptContext& scriptContext);
             static void AppendExternalFrameToStackTrace(CompoundString* bs, LPCWSTR functionName, LPCWSTR fileName, ULONG lineNumber, LONG characterPosition);
    
  • lib/Runtime/Language/JavascriptStackWalker.cpp+22 9 modified
    @@ -747,31 +747,39 @@ namespace Js
             return true;
         }
     
    -    BOOL JavascriptStackWalker::GetCallerWithoutInlinedFrames(JavascriptFunction ** ppFunc)
    +    BOOL JavascriptStackWalker::GetCallerWithoutInlinedFrames(_Out_opt_ JavascriptFunction ** ppFunc)
         {
             return GetCaller(ppFunc, /*includeInlineFrames*/ false);
         }
     
    -    BOOL JavascriptStackWalker::GetCaller(JavascriptFunction ** ppFunc, bool includeInlineFrames)
    +    BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction ** ppFunc, bool includeInlineFrames)
         {
             while (this->Walk(includeInlineFrames))
             {
                 if (this->IsJavascriptFrame())
                 {
                     Assert(entryExitRecord != NULL);
    -                *ppFunc = this->GetCurrentFunction();
    +                if (ppFunc)
    +                {
    +                    *ppFunc = this->GetCurrentFunction();
    +                }
                     AssertMsg(!this->shouldDetectPartiallyInitializedInterpreterFrame, "must have skipped first frame if needed");
                     return true;
                 }
             }
    -        *ppFunc = (JavascriptFunction*)this->scriptContext->GetLibrary()->GetNull();
    +        if (ppFunc)
    +        {
    +            *ppFunc = nullptr;
    +        }
             return false;
         }
     
    -    BOOL JavascriptStackWalker::GetNonLibraryCodeCaller(JavascriptFunction ** ppFunc)
    +    BOOL JavascriptStackWalker::GetNonLibraryCodeCaller(_Out_opt_ JavascriptFunction ** ppFunc)
         {
             while (this->GetCaller(ppFunc))
             {
    +            Assert(ppFunc != nullptr);
    +            __analysis_assume(ppFunc != nullptr);
                 if (!(*ppFunc)->IsLibraryCode())
                 {
                     return true;
    @@ -801,10 +809,12 @@ namespace Js
             }
         }
     
    -    bool JavascriptStackWalker::GetDisplayCaller(JavascriptFunction ** ppFunc)
    +    bool JavascriptStackWalker::GetDisplayCaller(_Out_opt_ JavascriptFunction ** ppFunc)
         {
             while (this->GetCaller(ppFunc))
             {
    +            Assert(ppFunc != nullptr);
    +            __analysis_assume(ppFunc != nullptr);
                 if (IsDisplayCaller(*ppFunc))
                 {
                     return true;
    @@ -1104,19 +1114,22 @@ namespace Js
             return (threadContext->GetScriptEntryExit() != NULL);
         }
     
    -    BOOL JavascriptStackWalker::GetCaller(JavascriptFunction** ppFunc, ScriptContext* scriptContext)
    +    BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction** ppFunc, ScriptContext* scriptContext)
         {
             if (!IsWalkable(scriptContext))
             {
    -            *ppFunc = nullptr;
    +            if (ppFunc)
    +            {
    +                *ppFunc = nullptr;
    +            }
                 return FALSE;
             }
     
             JavascriptStackWalker walker(scriptContext);
             return walker.GetCaller(ppFunc);
         }
     
    -    BOOL JavascriptStackWalker::GetCaller(JavascriptFunction** ppFunc, uint32* byteCodeOffset, ScriptContext* scriptContext)
    +    BOOL JavascriptStackWalker::GetCaller(_Out_opt_ JavascriptFunction** ppFunc, uint32* byteCodeOffset, ScriptContext* scriptContext)
         {
             JavascriptStackWalker walker(scriptContext);
             if (walker.GetCaller(ppFunc))
    
  • lib/Runtime/Language/JavascriptStackWalker.h+6 6 modified
    @@ -184,9 +184,9 @@ namespace Js
             ~JavascriptStackWalker() { inlinedFrameWalker.Close(); }
     #endif
             BOOL Walk(bool includeInlineFrames = true);
    -        BOOL GetCaller(JavascriptFunction ** ppFunc, bool includeInlineFrames = true);
    -        BOOL GetCallerWithoutInlinedFrames(JavascriptFunction ** ppFunc);
    -        BOOL GetNonLibraryCodeCaller(JavascriptFunction ** ppFunc);
    +        BOOL GetCaller(_Out_opt_ JavascriptFunction ** ppFunc, bool includeInlineFrames = true);
    +        BOOL GetCallerWithoutInlinedFrames(_Out_opt_ JavascriptFunction ** ppFunc);
    +        BOOL GetNonLibraryCodeCaller(_Out_opt_ JavascriptFunction ** ppFunc);
             BOOL WalkToTarget(JavascriptFunction * funcTarget);
             BOOL WalkToArgumentsFrame(ArgumentsObject *argsObj);
     
    @@ -237,13 +237,13 @@ namespace Js
             bool IsCurrentPhysicalFrameForLoopBody() const;
     
             // noinline, we want to use own stack frame.
    -        static _NOINLINE BOOL GetCaller(JavascriptFunction** ppFunc, ScriptContext* scriptContext);
    -        static _NOINLINE BOOL GetCaller(JavascriptFunction** ppFunc, uint32* byteCodeOffset, ScriptContext* scriptContext);
    +        static _NOINLINE BOOL GetCaller(_Out_opt_ JavascriptFunction** ppFunc, ScriptContext* scriptContext);
    +        static _NOINLINE BOOL GetCaller(_Out_opt_ JavascriptFunction** ppFunc, uint32* byteCodeOffset, ScriptContext* scriptContext);
             static _NOINLINE bool GetThis(Var* pThis, int moduleId, ScriptContext* scriptContext);
             static _NOINLINE bool GetThis(Var* pThis, int moduleId, JavascriptFunction* func, ScriptContext* scriptContext);
     
             static bool IsDisplayCaller(JavascriptFunction* func);
    -        bool GetDisplayCaller(JavascriptFunction ** ppFunc);
    +        bool GetDisplayCaller(_Out_opt_ JavascriptFunction ** ppFunc);
             PCWSTR GetCurrentNativeLibraryEntryName() const;
             static bool IsLibraryStackFrameEnabled(Js::ScriptContext * scriptContext);
             static bool IsWalkable(ScriptContext *scriptContext);
    
  • lib/Runtime/Library/ArgumentsObject.cpp+1 1 modified
    @@ -60,7 +60,7 @@ namespace Js
                 break;
             }
     
    -        if (funcCaller == nullptr || JavascriptOperators::GetTypeId(funcCaller) == TypeIds_Null)
    +        if (funcCaller == nullptr)
             {
                 return scriptContext->GetLibrary()->GetNull();
             }
    
  • lib/Runtime/Library/GlobalObject.cpp+15 10 modified
    @@ -685,17 +685,22 @@ namespace Js
                 if (args.Info.Flags & CallFlags_ExtraArg)
                 {
                     JavascriptFunction* pfuncCaller = nullptr;
    -                JavascriptStackWalker::GetCaller(&pfuncCaller, scriptContext);
                     // If we are non-hidden call to eval then look for the "this" object in the frame display if the caller is a lambda else get "this" from the caller's frame.
     
    -                FunctionInfo* functionInfo = pfuncCaller->GetFunctionInfo();
    -                if (functionInfo != nullptr && (functionInfo->IsLambda() || functionInfo->IsClassConstructor()))
    +                bool successful = false;
    +                if (JavascriptStackWalker::GetCaller(&pfuncCaller, scriptContext))
                     {
    -                    Var defaultInstance = (moduleID == kmodGlobal) ? JavascriptOperators::OP_LdRoot(scriptContext)->ToThis() : (Var)JavascriptOperators::GetModuleRoot(moduleID, scriptContext);
    -                    varThis = JavascriptOperators::OP_GetThisScoped(environment, defaultInstance, scriptContext);
    -                    UpdateThisForEval(varThis, moduleID, scriptContext, strictMode);
    +                    FunctionInfo* functionInfo = pfuncCaller->GetFunctionInfo();
    +                    if (functionInfo != nullptr && (functionInfo->IsLambda() || functionInfo->IsClassConstructor()))
    +                    {
    +                        Var defaultInstance = (moduleID == kmodGlobal) ? JavascriptOperators::OP_LdRoot(scriptContext)->ToThis() : (Var)JavascriptOperators::GetModuleRoot(moduleID, scriptContext);
    +                        varThis = JavascriptOperators::OP_GetThisScoped(environment, defaultInstance, scriptContext);
    +                        UpdateThisForEval(varThis, moduleID, scriptContext, strictMode);
    +                        successful = true;
    +                    }
                     }
    -                else
    +
    +                if (!successful)
                     {
                         JavascriptStackWalker::GetThis(&varThis, moduleID, scriptContext);
                         UpdateThisForEval(varThis, moduleID, scriptContext, strictMode);
    @@ -792,7 +797,7 @@ namespace Js
                 ArenaAllocator tempAlloc(_u("ValidateSyntaxArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory);
     
                 size_t cchSource = sourceLength;
    -            size_t cbUtf8Buffer = (cchSource + 1) * 3;
    +            size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(sourceLength);
                 LPUTF8 utf8Source = AnewArray(&tempAlloc, utf8char_t, cbUtf8Buffer);
                 Assert(cchSource < MAXLONG);
                 size_t cbSource = utf8::EncodeIntoAndNullTerminate(utf8Source, source, static_cast< charcount_t >(cchSource));
    @@ -864,7 +869,7 @@ namespace Js
             BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
             {
                 uint cchSource = sourceLength;
    -            size_t cbUtf8Buffer = (cchSource + 1) * 3;
    +            size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(cchSource);
     
                 ArenaAllocator tempArena(_u("EvalHelperArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
                 LPUTF8 utf8Source = AnewArray(&tempArena, utf8char_t, cbUtf8Buffer);
    @@ -1024,7 +1029,7 @@ namespace Js
             BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
             {
                 size_t cchSource = sourceLength;
    -            size_t cbUtf8Buffer = (cchSource + 1) * 3;
    +            size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(sourceLength);
     
                 ArenaAllocator tempArena(_u("EvalHelperArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
                 LPUTF8 utf8Source = AnewArray(&tempArena, utf8char_t, cbUtf8Buffer);
    
  • lib/Runtime/Library/JavascriptArray.cpp+16 7 modified
    @@ -3088,7 +3088,8 @@ namespace Js
     
             if (JavascriptArray::Is(pDestObj))
             {
    -            pDestArray = JavascriptArray::FromVar(pDestObj);
    +            // ConcatArgs function expects to work on the Var array so we are ensuring it.
    +            pDestArray = EnsureNonNativeArray(JavascriptArray::FromVar(pDestObj));
             }
     
             T idxDest = startIdxDest;
    @@ -3217,11 +3218,13 @@ namespace Js
                         ++idxDest;
                     }
                 }
    +
    +            firstPromotedItemIsSpreadable = false;
             }
             if (!pDestArray)
             {
                 JS_REENTRANT(jsReentLock, pDestObj->SetProperty(PropertyIds::length, ConvertToIndex<T, Var>(idxDest, scriptContext), Js::PropertyOperation_None, nullptr));
    -       }
    +        }
             else if (pDestArray->GetLength() != ConvertToIndex<T, uint32>(idxDest, scriptContext))
             {
                 pDestArray->SetLength(ConvertToIndex<T, uint32>(idxDest, scriptContext));
    @@ -5462,19 +5465,25 @@ namespace Js
                 }
     
                 // During the loop below we are going to reverse the segments list. The head segment will become the last segment.
    -            // We have to verify that the current head segment is not the inlined segement, otherwise due to shuffling below, the inlined segment will no longer
    -            // be the head and that can create issue down the line. Create new segment if it is an inlined segment.
    -            if (pArr->head && pArr->head->next)
    +            // We have to verify that the current head segment is not the inilined segement, otherwise due to shuffling below (of EnsureHeadStartsFromZero call below), the inlined segment will no longer
    +            // be the head and that can create issue down the line. Create new segment if it is an inilined segment.
    +            if (pArr->head && (pArr->head->next || (pArr->head->left + pArr->head->length) < length))
                 {
                     if (isIntArray)
                     {
                         CopyHeadIfInlinedHeadSegment<int32>(pArr, recycler);
    -                    ReallocateNonLeafLastSegmentIfLeaf<int32>(pArr, recycler);
    +                    if (pArr->head->next)
    +                    {
    +                        ReallocateNonLeafLastSegmentIfLeaf<int32>(pArr, recycler);
    +                    }
                     }
                     else if (isFloatArray)
                     {
                         CopyHeadIfInlinedHeadSegment<double>(pArr, recycler);
    -                    ReallocateNonLeafLastSegmentIfLeaf<double>(pArr, recycler);
    +                    if (pArr->head->next)
    +                    {
    +                        ReallocateNonLeafLastSegmentIfLeaf<double>(pArr, recycler);
    +                    }
                     }
                     else
                     {
    
  • lib/Runtime/Library/JavascriptFunction.cpp+14 5 modified
    @@ -621,13 +621,20 @@ namespace Js
             /// Check Argument[0] has internal [[Call]] property
             /// If not, throw TypeError
             ///
    -        if (args.Info.Count == 0 || !JavascriptConversion::IsCallable(args[0]))
    +        uint argCount = args.Info.Count;
    +        if (callInfo.Flags & CallFlags_ExtraArg)
    +        {
    +            // The last argument is the "extra". Don't consider it in the logic below.
    +            // It will either remain in place (argCount == 1) or be copied.
    +            argCount--;
    +        }
    +        if (argCount == 0 || !JavascriptConversion::IsCallable(args[0]))
             {
                 JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedFunction, _u("Function.prototype.call"));
             }
     
             RecyclableObject *pFunc = RecyclableObject::FromVar(args[0]);
    -        if (args.Info.Count == 1)
    +        if (argCount == 1)
             {
                 args.Values[0] = scriptContext->GetLibrary()->GetUndefined();
             }
    @@ -2719,12 +2726,14 @@ void __cdecl _alloca_probe_16()
                     break;
                 }
     
    -            if (funcCaller->GetScriptContext() != requestContext && funcCaller->GetTypeId() == TypeIds_Null)
    +            if (funcCaller == nullptr)
                 {
    -                // There are cases where StackWalker might return null value from different scriptContext
    -                // Caller of this function expects nullValue from the requestContext.
    +                // We no longer return Null objects as JavascriptFunctions, so we don't have to worry about
    +                // cross-context null objects. We do want to clean up null pointers though, since some call
    +                // later in this function may depend on non-nullptr calls.
                     funcCaller = nullValue;
                 }
    +
                 if (ScriptFunction::Is(funcCaller))
                 {
                     // If this is the internal function of a generator function then return the original generator function
    
  • lib/Runtime/Library/ScriptFunction.cpp+18 3 modified
    @@ -706,14 +706,29 @@ namespace Js
     
         InlineCache * ScriptFunctionWithInlineCache::GetInlineCache(uint index)
         {
    -        Assert(this->m_inlineCaches != nullptr);
    -        Assert(index < this->GetInlineCacheCount());
    +        void** inlineCaches = this->GetInlineCaches();
    +        Assert(inlineCaches != nullptr);
    +        AssertOrFailFast(index < this->GetInlineCacheCount());
     #if DBG
             Assert(this->m_inlineCacheTypes[index] == InlineCacheTypeNone ||
                 this->m_inlineCacheTypes[index] == InlineCacheTypeInlineCache);
             this->m_inlineCacheTypes[index] = InlineCacheTypeInlineCache;
     #endif
    -        return reinterpret_cast<InlineCache *>(PointerValue(this->m_inlineCaches[index]));
    +        return reinterpret_cast<InlineCache *>(PointerValue(inlineCaches[index]));
    +    }
    +
    +    Field(void**) ScriptFunctionWithInlineCache::GetInlineCaches()
    +    {
    +        // If script function have inline caches pointing to function body and function body got reparsed we need to reset cache
    +        if (this->GetHasInlineCaches() &&
    +            !this->GetHasOwnInlineCaches() &&
    +            this->m_inlineCaches != this->GetFunctionBody()->GetInlineCaches())
    +        {
    +            Assert(this->GetFunctionBody()->GetCompileCount() > 1);
    +            this->SetInlineCachesFromFunctionBody();
    +        }
    +
    +        return this->m_inlineCaches;
         }
     
         void ScriptFunctionWithInlineCache::SetInlineCachesFromFunctionBody()
    
  • lib/Runtime/Library/ScriptFunction.h+1 1 modified
    @@ -180,7 +180,7 @@ namespace Js
             void ClearBorrowedInlineCacheOnFunctionObject();
             InlineCache * GetInlineCache(uint index);
             uint GetInlineCacheCount() { return inlineCacheCount; }
    -        Field(void**) GetInlineCaches() { return m_inlineCaches; }
    +        Field(void**) GetInlineCaches();
             bool GetHasOwnInlineCaches() { return hasOwnInlineCaches; }
             void SetInlineCachesFromFunctionBody();
             static uint32 GetOffsetOfInlineCaches() { return offsetof(ScriptFunctionWithInlineCache, m_inlineCaches); };
    
  • lib/Runtime/Types/ActivationObject.h+4 0 modified
    @@ -184,21 +184,25 @@ namespace Js
     
             static PropertyId GetCachedFuncCount(const PropertyIdArray *propIds)
             {
    +            AssertOrFailFast(propIds->extraSlots > 0);
                 return ActivationObjectEx::GetCachedScopeInfo(propIds)[0];
             }
     
             static PropertyId GetFirstFuncSlot(const PropertyIdArray *propIds)
             {
    +            AssertOrFailFast(propIds->extraSlots > 1);
                 return ActivationObjectEx::GetCachedScopeInfo(propIds)[1];
             }
     
             static PropertyId GetFirstVarSlot(const PropertyIdArray *propIds)
             {
    +            AssertOrFailFast(propIds->extraSlots > 2);
                 return ActivationObjectEx::GetCachedScopeInfo(propIds)[2];
             }
     
             static PropertyId GetLiteralObjectRef(const PropertyIdArray *propIds)
             {
    +            AssertOrFailFast(propIds->extraSlots > 3);
                 return ActivationObjectEx::GetCachedScopeInfo(propIds)[3];
             }
     
    
  • lib/Runtime/Types/SimpleDictionaryTypeHandler.cpp+10 10 modified
    @@ -1349,16 +1349,6 @@ namespace Js
                     instance->ChangeType();
                 }
     
    -            if(isUnordered)
    -            {
    -                TPropertyIndex propertyIndex;
    -                if(AsUnordered()->TryUndeleteProperty(instance, descriptor->propertyIndex, &propertyIndex))
    -                {
    -                    Assert(PropertyRecordStringHashComparer<TMapKey>::Equals(propertyMap->GetKeyAt(propertyIndex), TMapKey_OptionalConvertPropertyIdToPropertyRecord(scriptContext, propertyKey)));
    -                    descriptor = propertyMap->GetReferenceAt(propertyIndex);
    -                }
    -            }
    -
                 if (IsNotExtensibleSupported)
                 {
                     bool isForce = (flags & PropertyOperation_Force) != 0;
    @@ -1371,6 +1361,16 @@ namespace Js
                     }
                 }
     
    +            if(isUnordered)
    +            {
    +                TPropertyIndex propertyIndex;
    +                if(AsUnordered()->TryUndeleteProperty(instance, descriptor->propertyIndex, &propertyIndex))
    +                {
    +                    Assert(PropertyRecordStringHashComparer<TMapKey>::Equals(propertyMap->GetKeyAt(propertyIndex), TMapKey_OptionalConvertPropertyIdToPropertyRecord(scriptContext, propertyKey)));
    +                    descriptor = propertyMap->GetReferenceAt(propertyIndex);
    +                }
    +            }
    +
                 if(SupportsSwitchingToUnordered(scriptContext))
                 {
                     --numDeletedProperties;
    
  • lib/Runtime/Types/SimpleDictionaryUnorderedTypeHandler.cpp+5 1 modified
    @@ -101,7 +101,11 @@ namespace Js
             Assert(this->propertyMap->GetValueAt(existingPropertyIndex).Attributes & PropertyDeleted);
     
             const bool reused = TryReuseDeletedPropertyIndex(object, propertyIndex);
    -        Assert(reused); // at least one property index must have been free-listed since we're adding an existing deleted property
    +        if (!reused)
    +        {
    +            Assert(0); // at least one property index must have been free-listed since we're adding an existing deleted property
    +            return false;
    +        }
     
             if(*propertyIndex == existingPropertyIndex)
             {
    
  • test/AsmJs/badFunctionType.baseline+77 0 added
    @@ -0,0 +1,77 @@
    +
    
    +Running test 0: kFunctionIsAccessor
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 1: kFunctionIsClassConstructor & kFunctionIsBaseClassConstructor
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 2: kFunctionIsStaticMember
    
    +static functions are not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 3: kFunctionIsClassMember
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 4: kFunctionIsMethod
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 5: kFunctionCallsEval
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 6: kFunctionChildCallsEval
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 7: kFunctionUsesArguments
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 8: kFunctionHasWithStmt
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 9: kFunctionIsLambda
    
    +lambda functions are not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 10: kFunctionHasNonSimpleParameterList: Module destructuring
    
    +default, rest & destructuring args not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 11: kFunctionHasNonSimpleParameterList: function destructuring
    
    +default, rest & destructuring args not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 12: kFunctionHasNonSimpleParameterList: rest
    
    +default, rest & destructuring args not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 13: kFunctionHasDefaultArguments
    
    +default, rest & destructuring args not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 14: kFunctionIsModule
    
    +Warning test disabled
    
    +
    
    +Running test 15: asm.js function in Module
    
    +Warning test disabled
    
    +
    
    +Running test 16: kFunctionIsDefaultModuleExport
    
    +Warning test disabled
    
    +
    
    +Running test 17: kFunctionHasSuperReference
    
    +invalid function flags detected
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 18: kFunctionIsGenerator
    
    +generator functions are not allowed
    
    +Asm.js compilation failed.
    
    +
    
    +Running test 19: kFunctionIsAsync
    
    +async functions are not allowed
    
    +Asm.js compilation failed.
    
    
  • test/AsmJs/badFunctionType.js+267 0 added
    @@ -0,0 +1,267 @@
    +//-------------------------------------------------------------------------------------------------------
    +// Copyright (C) Microsoft. All rights reserved.
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    +//-------------------------------------------------------------------------------------------------------
    +const simpleAsmDef = `
    +function x(v) {
    +  v = v | 0;
    +  return v | 0;
    +}
    +return x;`;
    +
    +const tests = [{
    +  name: "kFunctionIsAccessor",
    +  test() { eval(`
    +    var o = {
    +      set m(stdlib) {
    +        "use asm"
    +        var I32 = stdlib.Int32Array;
    +        ${simpleAsmDef}
    +      }
    +    }
    +    o.m = 5;
    +  `);}
    +}, {
    +  name: "kFunctionIsClassConstructor & kFunctionIsBaseClassConstructor",
    +  test() { eval(`
    +    class BaseClass {}
    +    class MyClass extends BaseClass {
    +      f(a,b,c,d,e) {
    +        print(a);
    +      }
    +
    +      constructor() {
    +        "use asm";
    +        ${simpleAsmDef}
    +      }
    +    }
    +    var x = new MyClass("df");
    +    x(3);
    +  `);
    +  }
    +}, {
    +  name: "kFunctionIsStaticMember",
    +  test() { eval(`
    +    class MyClass {
    +      static asmModuleClassMember() {
    +        "use asm";
    +        ${simpleAsmDef}
    +      }
    +    }
    +    MyClass.asmModuleClassMember()(3);
    +  `);
    +  }
    +}, {
    +  name: "kFunctionIsClassMember",
    +  test() { eval(`
    +    class MyClass {
    +      asmModuleClassMember() {
    +        "use asm";
    +        ${simpleAsmDef}
    +      }
    +    }
    +    var v = new MyClass("df")
    +    v.asmModuleClassMember()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionIsMethod",
    +  test() {eval(`
    +    var obj = {
    +      asmModuleMethod() {
    +        "use asm";
    +        ${simpleAsmDef}
    +      }
    +    }
    +    obj.asmModuleMethod()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionCallsEval",
    +  test() { eval(`
    +    function asmModuleEval() {
    +      "use asm";
    +      eval("function bar() {console.log('in bar')}");
    +      ${simpleAsmDef}
    +    }
    +    asmModuleEval()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionChildCallsEval",
    +  test() { eval(`
    +    function asmModuleChildEval() {
    +      "use asm";
    +      function x(v) {
    +        v = v | 0;
    +        eval("function bar() {console.log('in bar')}");
    +        return v | 0;
    +      }
    +      return x;
    +    }
    +    asmModuleChildEval()();
    +  `)
    +  }
    +}, {
    +  name: "kFunctionUsesArguments",
    +  test() { eval(`
    +    function asmModuleArguments() {
    +      "use asm";
    +      arguments;
    +      ${simpleAsmDef}
    +    }
    +    asmModuleArguments();
    +  `)
    +  }
    +}, {
    +  name: "kFunctionHasWithStmt",
    +  test() { eval(`
    +    function asmModuleWith() {
    +      "use asm";
    +      with(5) {
    +        ${simpleAsmDef}
    +      }
    +    }
    +    asmModuleWith()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionIsLambda",
    +  test() { eval(`
    +    const asmModuleLambda = () => {
    +      "use asm";
    +      ${simpleAsmDef}
    +    }
    +    asmModuleLambda()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionHasNonSimpleParameterList: Module destructuring",
    +  test() { eval(`
    +    function asmModuleDestructuring({Math: {sin}}) {
    +      "use asm";
    +      function x(v) {
    +        v = +v;
    +        return +sin(+v);
    +      }
    +      return x;
    +    }
    +    asmModuleDestructuring({Math})(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionHasNonSimpleParameterList: function destructuring",
    +  test() { eval(`
    +    function asmModuleDestructuringChild() {
    +      "use asm";
    +      function x({v}) {
    +        v = +v;
    +        return +v;
    +      }
    +      return x;
    +    }
    +    asmModuleDestructuringChild()({v: 3});
    +  `)
    +  }
    +}, {
    +  name: "kFunctionHasNonSimpleParameterList: rest",
    +  test() { eval(`
    +    function asmModuleRest(...rest) {
    +      "use asm";
    +      ${simpleAsmDef}
    +    }
    +    asmModuleRest()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionHasDefaultArguments",
    +  test() { eval(`
    +    function asmModuleDefault(stdlib = {Math}) {
    +      "use asm";
    +      var sin = stdlib.Math.sin;
    +      function x(v) {
    +        v = +v;
    +        return +(+sin(+v));
    +      }
    +      return x;
    +    }
    +    asmModuleDefault()(3);
    +  `)
    +  }
    +}, {
    +  // Todo:: bug #12464098
    +  disabled: true,
    +  name: "kFunctionIsModule",
    +  test() { WScript.LoadModule(`
    +    "use asm"
    +    export function x(v) {
    +      v = v | 0;
    +      return v | 0;
    +    }`)
    +  }
    +}, {
    +  // found bugs in jsrt api
    +  disabled: true,
    +  name: "asm.js function in Module",
    +  test() {
    +    WScript.LoadModule(`
    +    function AsmDefaultExport() {
    +      "use asm"
    +      ${simpleAsmDef}
    +    }`)
    +  }
    +}, {
    +  disabled: true,
    +  name: "kFunctionIsDefaultModuleExport",
    +  test() {
    +    WScript.LoadModule(`
    +    export default function AsmDefaultExport() {
    +      "use asm"
    +      ${simpleAsmDef}
    +    }`)
    +  }
    +}, {
    +  name: "kFunctionHasSuperReference",
    +  test() { eval(`
    +    var obj = {
    +      asmModuleSuper() {
    +        "use asm";
    +        var a = super.toString;
    +        ${simpleAsmDef}
    +      }
    +    }
    +    obj.asmModuleSuper()(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionIsGenerator",
    +  test() { eval(`
    +    function* asmModuleGenerator() {
    +      "use asm";
    +      ${simpleAsmDef}
    +    }
    +    asmModuleGenerator().next().value(3);
    +  `)
    +  }
    +}, {
    +  name: "kFunctionIsAsync",
    +  test() { eval(`
    +    async function asmModuleAsync() {
    +      "use asm";
    +      ${simpleAsmDef}
    +    }
    +    asmModuleAsync().then(f => f(3));
    +  `)
    +  }
    +}];
    +
    +const start = WScript.Arguments[0] || 0;
    +for (let i = start; i < tests.length; ++i) {
    +  const {disabled, name, test} = tests[i];
    +  console.log(`\nRunning test ${i}: ${name}`);
    +  if (disabled) {
    +    console.log("Warning test disabled");
    +  } else {
    +    test();
    +  }
    +}
    \ No newline at end of file
    
  • test/AsmJs/bug12239366.js+25 0 added
    @@ -0,0 +1,25 @@
    +//-------------------------------------------------------------------------------------------------------
    
    +// Copyright (C) Microsoft. All rights reserved.
    
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    
    +//-------------------------------------------------------------------------------------------------------
    
    +
    
    +function asmModule() {
    
    +  "use asm";
    
    +
    
    +  let a = [1];
    
    +  for (let i = 0; i < 2; i++) { // JIT
    
    +    a[0] = 1;
    
    +    if (i > 0) {
    
    +      a[0] = {}; // the array type changed, bailout!!
    
    +    }
    
    +  }
    
    +
    
    +  function f(v) {
    
    +    v = v | 0;
    
    +    return v | 0;
    
    +  }
    
    +  return f;
    
    +}
    
    +
    
    +asmModule(1);
    
    +print("PASSED");
    
    
  • test/AsmJs/rlexe.xml+18 0 modified
    @@ -919,6 +919,19 @@
           <compile-flags>-testtrace:asmjs -maic:1</compile-flags>
         </default>
       </test>
    +  <test>
    +    <default>
    +      <files>bug12239366.js</files>
    +      <compile-flags>-lic:1 -bgjit-</compile-flags>
    +    </default>
    +  </test>
    +  <test>
    +    <default>
    +      <files>badFunctionType.js</files>
    +      <baseline>badFunctionType.baseline</baseline>
    +      <compile-flags>-testtrace:asmjs</compile-flags>
    +    </default>
    +  </test>
       <test>
         <default>
           <files>bugGH2270.js</files>
    @@ -982,4 +995,9 @@
           <tags>exclude_drt</tags>
         </default>
       </test>
    +  <test>
    +    <default>
    +      <files>trackdeferredonreparse.js</files>
    +    </default>
    +  </test>
     </regress-exe>
    
  • test/AsmJs/trackdeferredonreparse.js+174 0 added
    @@ -0,0 +1,174 @@
    +//-------------------------------------------------------------------------------------------------------
    +// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    +//-------------------------------------------------------------------------------------------------------
    +
    +print = function(){};
    +(function () {  
    +
    +  assertPromiseResult = function(promise, success, fail) {
    +
    +    if (!success) success = () => {};
    +
    +    failWithMessage = (msg) => eval("print(msg)");
    +    if (!fail) {
    +      fail = result => failWithMessage("assertPromiseResult failed: " + result);
    +    }
    +
    +    var test_promise =
    +        promise.then(
    +          result => {
    +            try {
    +              success(result);
    +            } catch (e) {
    +              failWithMessage(e);
    +            }
    +          },
    +          result => {
    +            fail(result);
    +          }
    +        )
    +        .then((x)=> {
    +          if (--promiseTestCount == 0) testRunner.notifyDone();
    +        });
    +
    +    if (!promiseTestChain) promiseTestChain = Promise.resolve();
    +    // waitUntilDone is idempotent.
    +    testRunner.waitUntilDone();
    +    ++promiseTestCount;
    +    return promiseTestChain.then(test_promise);
    +  };
    +
    +
    + assertUnoptimized = function assertUnoptimized(fun, sync_opt, name_opt) {
    +    if (sync_opt === undefined) sync_opt = "";
    +    var opt_status = OptimizationStatus(fun, sync_opt);
    +    // Tests that use assertOptimized() do not make sense if --always-opt
    +    // option is provided. Such tests must add --no-always-opt to flags comment.
    +    assertFalse((opt_status & V8OptimizationStatus.kAlwaysOptimize) !== 0,
    +                "test does not make sense with --always-opt");
    +    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0, name_opt);
    +    if ((opt_status & V8OptimizationStatus.kMaybeDeopted) !== 0) {
    +      // When --deopt-every-n-times flag is specified it's no longer guaranteed
    +      // that particular function is still deoptimized, so keep running the test
    +      // to stress test the deoptimizer.
    +      return;
    +    }
    +    assertFalse((opt_status & V8OptimizationStatus.kOptimized) !== 0, name_opt);
    +  }
    +
    +
    +
    +
    +
    +
    + 
    +  assertOptimized = function assertOptimized(fun, sync_opt, name_opt) {
    +    if (sync_opt === undefined) sync_opt = "";
    +    var opt_status = OptimizationStatus(fun, sync_opt);
    +    // Tests that use assertOptimized() do not make sense if --no-opt
    +    // option is provided. Such tests must add --opt to flags comment.
    +    assertFalse((opt_status & V8OptimizationStatus.kNeverOptimize) !== 0,
    +                "test does not make sense with --no-opt");
    +    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0, name_opt);
    +    if ((opt_status & V8OptimizationStatus.kMaybeDeopted) !== 0) {
    +      // When --deopt-every-n-times flag is specified it's no longer guaranteed
    +      // that particular function is still optimized, so keep running the test
    +      // to stress test the deoptimizer.
    +      return;
    +    }
    +    assertTrue((opt_status & V8OptimizationStatus.kOptimized) !== 0, name_opt);
    +  }
    +
    +  isNeverOptimize = function isNeverOptimize() {
    +    var opt_status = OptimizationStatus(undefined, "");
    +    return (opt_status & V8OptimizationStatus.kNeverOptimize) !== 0;
    +  }
    +
    +  isAlwaysOptimize = function isAlwaysOptimize() {
    +    var opt_status = OptimizationStatus(undefined, "");
    +    return (opt_status & V8OptimizationStatus.kAlwaysOptimize) !== 0;
    +  }
    +
    +  isInterpreted = function isInterpreted(fun) {
    +    var opt_status = OptimizationStatus(fun, "");
    +    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
    +               "not a function");
    +    return (opt_status & V8OptimizationStatus.kOptimized) === 0 &&
    +           (opt_status & V8OptimizationStatus.kInterpreted) !== 0;
    +  }
    +
    +  isOptimized = function isOptimized(fun) {
    +    var opt_status = OptimizationStatus(fun, "");
    +    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
    +               "not a function");
    +    return (opt_status & V8OptimizationStatus.kOptimized) !== 0;
    +  }
    +
    +  isCrankshafted = function isCrankshafted(fun) {
    +    var opt_status = OptimizationStatus(fun, "");
    +    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
    +               "not a function");
    +    return (opt_status & V8OptimizationStatus.kOptimized) !== 0 &&
    +           (opt_status & V8OptimizationStatus.kTurboFanned) === 0;
    +  }
    +
    +  isTurboFanned = function isTurboFanned(fun) {
    +    var opt_status = OptimizationStatus(fun, "");
    +    assertTrue((opt_status & V8OptimizationStatus.kIsFunction) !== 0,
    +               "not a function");
    +    return (opt_status & V8OptimizationStatus.kOptimized) !== 0 &&
    +           (opt_status & V8OptimizationStatus.kTurboFanned) !== 0;
    +  }
    +
    +})();
    +
    +
    +// Copyright 2015 the V8 project authors. All rights reserved.
    +// Use of this source code is governed by a BSD-style license that can be
    +// found in the LICENSE file.
    +
    +// Flags: --allow-natives-syntax
    +
    +assertEquals = print;
    +
    +var m = (function() {
    +  "use asm";
    +  function f(x) {
    +    return x < 0;
    +  }
    +  function g(x) {
    +    return 0 < x;
    +  }
    +  return { f: f, g: g };
    +})();
    +var f = m.f;
    +var g = m.g;
    +
    +var counter = 0;
    +
    +function deopt(f) {
    +  return {
    +    toString : function() {
    +      print(f);
    +      counter++;
    +      return "2";
    +    }
    +  };
    +}
    +
    +assertEquals(false, f(deopt(f)));
    +assertEquals(1, counter);
    +
    +assertEquals(true, g(deopt(g)));
    +assertEquals(2, counter);
    +
    +print(f);
    +assertEquals(false, f(deopt(f)));
    +assertEquals(3, counter);
    +
    +print(g);
    +assertEquals(true, g(deopt(g)));
    +assertEquals(4, counter);
    +
    +WScript.Echo('pass');
    
  • test/Basics/DeleteAndReAddNonExtensible.js+20 0 added
    @@ -0,0 +1,20 @@
    +//-------------------------------------------------------------------------------------------------------
    +// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    +//-------------------------------------------------------------------------------------------------------
    +
    +var kNumProperties = 32;
    +
    +var o = {};
    +for (var i = 0; i < kNumProperties; ++i)
    +o['a' + i] = i;
    +
    +Object.preventExtensions(o); // IsNotExtensibleSupported && !this->VerifyIsExtensible
    +
    +for (var i = 0; i < kNumProperties; ++i)
    +delete o['a' + i];
    +
    +for (var i = 0; i < 0x21; ++i)
    +o['a0'] = 1; // calling TryUndeleteProperty again again
    +
    +WScript.Echo('pass');
    
  • test/Basics/rlexe.xml+5 0 modified
    @@ -311,6 +311,11 @@
           <compile-flags>-Intl-</compile-flags>
         </default>
       </test>
    +  <test>
    +    <default>
    +      <files>DeleteAndReAddNonExtensible.js</files>
    +    </default>
    +  </test>
       <test>
         <default>
           <files>Accessors.js</files>
    
  • test/es6/destructuring_catch.js+8 0 modified
    @@ -51,6 +51,14 @@ var tests = [
           assert.throws(function () { eval("function foo() {try {} catch([x]) { let x = 10;} }"); }, SyntaxError,  "Catch param as a pattern and matching name with let/const variable in body is not valid syntax", "Let/Const redeclaration");
    
           assert.throws(function () { eval("function foo() {try {} catch([x]) { function x() {} } }"); }, SyntaxError,  "Catch param as a pattern and matching name with function name in body is not valid syntax", "Let/Const redeclaration");
    
           assert.doesNotThrow(function () { eval("function foo() {try {} catch([x]) { var x = 10;} }"); },  "Catch param as a pattern and matching name with var declared name in body is valid syntax");
    
    +
    
    +      (function () {
    
    +        try {
    
    +        } catch ({x}) {
    
    +        var x = 1;
    
    +        }
    
    +        assert.areEqual(x, undefined, "Assignment inside the catch block should assign the value to the catch param not the body var");
    
    +      })();
    
         }
    
       },
    
       {
    
    
  • test/es6/destructuring_params_arguments_override.js+24 0 added
    @@ -0,0 +1,24 @@
    +//-------------------------------------------------------------------------------------------------------
    +// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    +//-------------------------------------------------------------------------------------------------------
    +
    +function f() {
    +    ({a = () => {
    +        let arguments;
    +    }} = 1);
    +
    +    arguments.x;
    +}
    +
    +f();
    +
    +function g() {
    +    ({a = ([arguments]) => {}} = 1);
    +
    +    arguments.x;
    +}
    +
    +g();
    +
    +WScript.Echo('pass');
    
  • test/es6/ProxyCall.js+12 0 added
    @@ -0,0 +1,12 @@
    +//-------------------------------------------------------------------------------------------------------
    +// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    +//-------------------------------------------------------------------------------------------------------
    +
    +function f() {
    +    arguments;
    +    WScript.Echo('pass');
    +}
    +
    +let call = new Proxy(Function.prototype.call, {}); // proxy calls set the flag
    +call.call(f);
    
  • test/es6/rlexe.xml+10 0 modified
    @@ -728,6 +728,11 @@
           <files>proxybug.js</files>
         </default>
       </test>
    +  <test>
    +    <default>
    +      <files>proxycall.js</files>
    +    </default>
    +  </test>
       <test>
         <default>
           <files>proxyenumremoval.js</files>
    @@ -900,6 +905,11 @@
           <compile-flags>-ES6Rest -ES6Classes -ES6Destructuring -ES6DefaultArgs -args summary -endargs</compile-flags>
         </default>
       </test>
    +  <test>
    +    <default>
    +      <files>destructuring_params_arguments_override.js</files>
    +    </default>
    +  </test>
       <test>
         <default>
           <files>destructuring_catch.js</files>
    
  • test/Function/argumentsLimits.baseline+1 1 modified
    @@ -1 +1 @@
    -65532
    
    +Out of memory
    
    
  • test/Function/argumentsLimits.js+6 1 modified
  • test/Function/deferredstuboob.js+17 0 added
    @@ -0,0 +1,17 @@
    +//-------------------------------------------------------------------------------------------------------
    +// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
    +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
    +//-------------------------------------------------------------------------------------------------------
    +
    +function test0() {
    +var func12 = function (arg1 = ( { get : function f1 () { }}
    +, { get : function f213 () { }}
    +, { get : function f214 () { }}
    +,(function f2() {}))) 
    +{
    +};
    +func12();
    +}
    +test0();
    +
    +WScript.Echo('pass');
    
  • test/Function/rlexe.xml+6 0 modified
    @@ -187,6 +187,12 @@
           <tags>exclude_dynapogo</tags>
         </default>
       </test>
    +  <test>
    +    <default>
    +      <files>deferredStubOob.js</files>
    +      <compile-flags>-force:deferparse -pageheap:2</compile-flags>
    +    </default>
    +  </test>
       <test>
         <default>
           <files>deferredWith.js</files>
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.