Skip to content

Commit

Permalink
[MERGE #6155 @pleath] ChakraCore servicing update for June, 2019
Browse files Browse the repository at this point in the history
Merge pull request #6155 from pleath:1906

This release addresses the following issues:

CVE-2019-0989
CVE-2019-0990
CVE-2019-0991
CVE-2019-0992
CVE-2019-0993
CVE-2019-1003
CVE-2019-1023
CVE-2019-1024
CVE-2019-1051
CVE-2019-1052
  • Loading branch information
pleath committed Jun 11, 2019
2 parents d797e3f + eabf77a commit 3d6226c
Show file tree
Hide file tree
Showing 23 changed files with 430 additions and 74 deletions.
1 change: 1 addition & 0 deletions Build/Common.Build.Default.props
Expand Up @@ -17,6 +17,7 @@
<PlatformToolset Condition="'$(BuildToolVersion)'=='12.0'">v120</PlatformToolset>
<PlatformToolset Condition="'$(BuildToolVersion)'=='14.0'">v140</PlatformToolset>
<PlatformToolset Condition="'$(BuildToolVersion)'=='15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(BuildToolVersion)'=='16.0'">v142</PlatformToolset>
</PropertyGroup>

<!-- Default ChakraDevConfigDir -->
Expand Down
2 changes: 1 addition & 1 deletion Build/NuGet/.pack-version
@@ -1 +1 @@
1.11.9
1.11.10
79 changes: 75 additions & 4 deletions lib/Backend/BackwardPass.cpp
Expand Up @@ -1645,6 +1645,8 @@ BackwardPass::ProcessLoop(BasicBlock * lastBlock)
{
Assert(loop->symsAssignedToInLoop == nullptr);
loop->symsAssignedToInLoop = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
Assert(loop->preservesNumberValue == nullptr);
loop->preservesNumberValue = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
}

FOREACH_BLOCK_BACKWARD_IN_RANGE_DEAD_OR_ALIVE(block, lastBlock, nullptr)
Expand Down Expand Up @@ -4316,7 +4318,10 @@ BackwardPass::ProcessNoImplicitCallDef(IR::Instr *const instr)
const bool transferArrayLengthSymUse = !!currentBlock->noImplicitCallArrayLengthSymUses->TestAndClear(dstSym->m_id);

IR::Opnd *const src = instr->GetSrc1();
if(!src || instr->GetSrc2())

// Stop attempting to transfer noImplicitCallUses symbol if the instr is not a transfer instr (based on the opcode's
// flags) or does not have the attributes to be a transfer instr (based on the existance of src and src2).
if(!src || (instr->GetSrc2() && !OpCodeAttr::NonIntTransfer(instr->m_opcode)))
{
return;
}
Expand Down Expand Up @@ -5004,16 +5009,24 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
return;
}

instr->GetDst()->AsIndirOpnd()->AllowConversion(true);
IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
if (!baseValueType.IsNotNativeArray() &&
(!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
!currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
!(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
{
// There is an upwards-exposed use of a native array. Since the array referenced by this instruction can be aliased,
// this instruction needs to bail out if it converts the native array even if this array specifically is not
// upwards-exposed.
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
if (!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar())
{
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
}
else
{
// We are assuming that array conversion is impossible here, so make sure we execute code that fails if conversion does happen.
instr->GetDst()->AsIndirOpnd()->AllowConversion(false);
}
}

if(baseOpnd->IsArrayRegOpnd() && baseOpnd->AsArrayRegOpnd()->EliminatedUpperBoundCheck())
Expand Down Expand Up @@ -7410,6 +7423,52 @@ BackwardPass::TrackFloatSymEquivalence(IR::Instr *const instr)
}
}

bool
BackwardPass::SymIsIntconstOrSelf(Sym *sym, IR::Opnd *opnd)
{
Assert(sym->IsStackSym());
if (!opnd->IsRegOpnd())
{
return false;
}
StackSym *opndSym = opnd->AsRegOpnd()->m_sym;

if (sym == opndSym)
{
return true;
}

if (!opndSym->IsSingleDef())
{
return false;
}

if (opndSym->GetInstrDef()->m_opcode == Js::OpCode::LdC_A_I4)
{
return true;
}

return false;
}

bool
BackwardPass::InstrPreservesNumberValues(IR::Instr *instr, Sym *defSym)
{
if (instr->m_opcode == Js::OpCode::Ld_A)
{
if (instr->GetSrc1()->IsRegOpnd())
{
IR::RegOpnd *src1 = instr->GetSrc1()->AsRegOpnd();
if (src1->m_sym->IsSingleDef())
{
instr = src1->m_sym->GetInstrDef();
}
}
}
return (OpCodeAttr::ProducesNumber(instr->m_opcode) ||
(instr->m_opcode == Js::OpCode::Add_A && this->SymIsIntconstOrSelf(defSym, instr->GetSrc1()) && this->SymIsIntconstOrSelf(defSym, instr->GetSrc2())));
}

bool
BackwardPass::ProcessDef(IR::Opnd * opnd)
{
Expand All @@ -7424,7 +7483,19 @@ BackwardPass::ProcessDef(IR::Opnd * opnd)
this->InvalidateCloneStrCandidate(opnd);
if ((tag == Js::BackwardPhase) && IsPrePass())
{
this->currentPrePassLoop->symsAssignedToInLoop->Set(sym->m_id);
bool firstDef = !this->currentPrePassLoop->symsAssignedToInLoop->TestAndSet(sym->m_id);

if (firstDef)
{
if (this->InstrPreservesNumberValues(this->currentInstr, sym))
{
this->currentPrePassLoop->preservesNumberValue->Set(sym->m_id);
}
}
else if (!this->InstrPreservesNumberValues(this->currentInstr, sym))
{
this->currentPrePassLoop->preservesNumberValue->Clear(sym->m_id);
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/Backend/BackwardPass.h
Expand Up @@ -36,6 +36,9 @@ class BackwardPass
bool ProcessDef(IR::Opnd * opnd);
void ProcessTransfers(IR::Instr * instr);
void ProcessFieldKills(IR::Instr * instr);
bool SymIsIntconstOrSelf(Sym *sym, IR::Opnd *opnd);
bool InstrPreservesNumberValues(IR::Instr *instr, Sym *defSym);

template<typename T> void ClearBucketsOnFieldKill(IR::Instr *instr, HashTable<T> *table);
StackSym* ProcessByteCodeUsesDst(IR::ByteCodeUsesInstr * byteCodeUsesInstr);
const BVSparse<JitArenaAllocator>* ProcessByteCodeUsesSrcs(IR::ByteCodeUsesInstr * byteCodeUsesInstr);
Expand Down
2 changes: 2 additions & 0 deletions lib/Backend/FlowGraph.h
Expand Up @@ -588,6 +588,7 @@ class Loop
// cleanup in PreOptPeep in the pre-pass of a loop. For aggressively transferring
// values in prepass, we need to know if a source sym was ever assigned to in a loop.
BVSparse<JitArenaAllocator> *symsAssignedToInLoop;
BVSparse<JitArenaAllocator> *preservesNumberValue;

BailOutInfo * bailOutInfo;
IR::BailOutInstr * toPrimitiveSideEffectCheck;
Expand Down Expand Up @@ -733,6 +734,7 @@ class Loop
symsAssignedToInLoop(nullptr),
needImplicitCallBailoutChecksForJsArrayCheckHoist(false),
inductionVariables(nullptr),
preservesNumberValue(nullptr),
dominatingLoopCountableBlock(nullptr),
loopCount(nullptr),
loopCountBasedBoundBaseSyms(nullptr),
Expand Down
69 changes: 68 additions & 1 deletion lib/Backend/GlobOpt.cpp
Expand Up @@ -1244,7 +1244,7 @@ void GlobOpt::InsertValueCompensation(
{
IR::Instr *const newInstr =
IR::Instr::New(
Js::OpCode::Ld_I4,
Js::OpCode::Ld_A,
IR::RegOpnd::New(mergedHeadSegmentLengthSym, mergedHeadSegmentLengthSym->GetType(), func),
IR::RegOpnd::New(predecessorHeadSegmentLengthSym, predecessorHeadSegmentLengthSym->GetType(), func),
func);
Expand Down Expand Up @@ -2694,6 +2694,48 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
return instrNext;
}

bool
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
{
if (opnd == nullptr)
{
return false;
}

if (opnd->m_sym->m_isNotNumber)
{
return true;
}

if (!inGlobOpt)
{
return false;
}

if (opnd->GetValueType().IsNumber() || currentBlock->globOptData.IsTypeSpecialized(opnd->m_sym))
{
if (!this->IsLoopPrePass())
{
return false;
}

Value * opndValue = this->currentBlock->globOptData.FindValue(opnd->m_sym);
ValueInfo * opndValueInfo = opndValue ? opndValue->GetValueInfo() : nullptr;
if (!opndValueInfo)
{
return true;
}
if (this->prePassLoop->preservesNumberValue->Test(opnd->m_sym->m_id))
{
return false;
}

return !this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
}

return true;
}

bool
GlobOpt::OptTagChecks(IR::Instr *instr)
{
Expand Down Expand Up @@ -12827,6 +12869,26 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr)
it.RemoveCurrent();
}
}
else if(kills.KillsObjectArraysWithNoMissingValues())
{
// Some operations may kill objects with arrays-with-no-missing-values in unlikely circumstances. Convert their value types to likely
// versions so that the checks have to be redone.
for(auto it = valuesToKillOnCalls->GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
{
Value *const value = it.CurrentValue();
ValueInfo *const valueInfo = value->GetValueInfo();
Assert(
valueInfo->IsArrayOrObjectWithArray() ||
valueInfo->IsOptimizedVirtualTypedArray() ||
valueInfo->IsOptimizedTypedArray() && valueInfo->AsArrayValueInfo()->HeadSegmentLengthSym());
if(!valueInfo->IsArrayOrObjectWithArray() || valueInfo->IsArray() || !valueInfo->HasNoMissingValues())
{
continue;
}
ChangeValueType(nullptr, value, valueInfo->Type().ToLikely(), false);
it.RemoveCurrent();
}
}

if(kills.KillsNativeArrays())
{
Expand Down Expand Up @@ -13358,6 +13420,11 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
{
kills.SetKillsArrayLengths();
}

if(doArrayMissingValueCheckHoist && !(useValueTypes && arrayValueType.IsArray()))
{
kills.SetKillsObjectArraysWithNoMissingValues();
}
break;
}

Expand Down
8 changes: 7 additions & 1 deletion lib/Backend/GlobOpt.h
Expand Up @@ -317,6 +317,7 @@ class JsArrayKills
{
bool killsAllArrays : 1;
bool killsArraysWithNoMissingValues : 1;
bool killsObjectArraysWithNoMissingValues : 1;
bool killsNativeArrays : 1;
bool killsArrayHeadSegments : 1;
bool killsArrayHeadSegmentLengths : 1;
Expand All @@ -342,6 +343,9 @@ class JsArrayKills
bool KillsArraysWithNoMissingValues() const { return killsArraysWithNoMissingValues; }
void SetKillsArraysWithNoMissingValues() { killsArraysWithNoMissingValues = true; }

bool KillsObjectArraysWithNoMissingValues() const { return killsObjectArraysWithNoMissingValues; }
void SetKillsObjectArraysWithNoMissingValues() { killsObjectArraysWithNoMissingValues = true; }

bool KillsNativeArrays() const { return killsNativeArrays; }
void SetKillsNativeArrays() { killsNativeArrays = true; }

Expand Down Expand Up @@ -769,6 +773,8 @@ class GlobOpt
const bool lossy = false, const bool forceInvariantHoisting = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd** srcOpndPtr, Value *const srcVal);
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const;

public:
static bool IsTypeSpecPhaseOff(Func const * func);
static bool DoAggressiveIntTypeSpec(Func const * func);
Expand Down Expand Up @@ -891,7 +897,7 @@ class GlobOpt
void KillLiveFields(StackSym * stackSym, BVSparse<JitArenaAllocator> * bv);
void KillLiveFields(PropertySym * propertySym, BVSparse<JitArenaAllocator> * bv);
void KillLiveFields(BVSparse<JitArenaAllocator> *const fieldsToKill, BVSparse<JitArenaAllocator> *const bv) const;
void KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
void KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
void KillAllFields(BVSparse<JitArenaAllocator> * bv);
void SetAnyPropertyMayBeWrittenTo();
void AddToPropertiesWrittenTo(Js::PropertyId propertyId);
Expand Down
34 changes: 22 additions & 12 deletions lib/Backend/GlobOptFields.cpp
Expand Up @@ -208,7 +208,7 @@ void GlobOpt::KillLiveFields(BVSparse<JitArenaAllocator> *const fieldsToKill, BV
}

void
GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func)
GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func)
{
IR::RegOpnd *indexOpnd = indirOpnd->GetIndexOpnd();

Expand All @@ -225,14 +225,7 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> *
// - We check the type specialization status for the sym as well. For the purpose of doing kills, we can assume that
// if type specialization happened, that fields don't need to be killed. Note that they may be killed in the next
// pass based on the value.
if (func->GetThisOrParentInlinerHasArguments() ||
(
indexOpnd &&
(
indexOpnd->m_sym->m_isNotNumber ||
(inGlobOpt && !indexOpnd->GetValueType().IsNumber() && !currentBlock->globOptData.IsTypeSpecialized(indexOpnd->m_sym))
)
))
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt))
{
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
SetAnyPropertyMayBeWrittenTo();
Expand All @@ -248,6 +241,23 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> *
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
this->KillAllObjectTypes(bv);
}
else if ((!valueOpnd || valueOpnd->IsVar()) && this->objectTypeSyms != nullptr)
{
// If we wind up converting a native array, block final-type opt at this point, because we could evolve
// to a type with the wrong type ID. Do this by noting that we may have evolved any type and so must
// check it before evolving it further.
IR::RegOpnd *baseOpnd = indirOpnd->GetBaseOpnd();
Value * baseValue = baseOpnd ? this->currentBlock->globOptData.FindValue(baseOpnd->m_sym) : nullptr;
ValueInfo * baseValueInfo = baseValue ? baseValue->GetValueInfo() : nullptr;
if (!baseValueInfo || !baseValueInfo->IsNotNativeArray())
{
if (this->currentBlock->globOptData.maybeWrittenTypeSyms == nullptr)
{
this->currentBlock->globOptData.maybeWrittenTypeSyms = JitAnew(this->alloc, BVSparse<JitArenaAllocator>, this->alloc);
}
this->currentBlock->globOptData.maybeWrittenTypeSyms->Or(this->objectTypeSyms);
}
}
}
}

Expand Down Expand Up @@ -340,7 +350,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
case Js::OpCode::StElemI_A_Strict:
Assert(dstOpnd != nullptr);
KillLiveFields(this->lengthEquivBv, bv);
KillLiveElems(dstOpnd->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
KillLiveElems(dstOpnd->AsIndirOpnd(), instr->GetSrc1(), bv, inGlobOpt, instr->m_func);
if (inGlobOpt)
{
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
Expand All @@ -350,7 +360,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
case Js::OpCode::InitComputedProperty:
case Js::OpCode::InitGetElemI:
case Js::OpCode::InitSetElemI:
KillLiveElems(dstOpnd->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
KillLiveElems(dstOpnd->AsIndirOpnd(), instr->GetSrc1(), bv, inGlobOpt, instr->m_func);
if (inGlobOpt)
{
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
Expand All @@ -360,7 +370,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
case Js::OpCode::DeleteElemI_A:
case Js::OpCode::DeleteElemIStrict_A:
Assert(dstOpnd != nullptr);
KillLiveElems(instr->GetSrc1()->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
KillLiveElems(instr->GetSrc1()->AsIndirOpnd(), nullptr, bv, inGlobOpt, instr->m_func);
break;

case Js::OpCode::DeleteFld:
Expand Down
9 changes: 8 additions & 1 deletion lib/Backend/IR.cpp
Expand Up @@ -3307,7 +3307,14 @@ bool Instr::TransfersSrcValue()

// Consider: Add opcode attribute to indicate whether the opcode would use the value or not

return this->GetDst() != nullptr && this->GetSrc2() == nullptr && !OpCodeAttr::DoNotTransfer(this->m_opcode) && !this->CallsAccessor();
return
this->GetDst() != nullptr &&

// The lack of a Src2 does not always indicate that the instr is not a transfer instr (ex: StSlotChkUndecl).
(this->GetSrc2() == nullptr || OpCodeAttr::NonIntTransfer(this->m_opcode)) &&

!OpCodeAttr::DoNotTransfer(this->m_opcode) &&
!this->CallsAccessor();
}


Expand Down

0 comments on commit 3d6226c

Please sign in to comment.