Skip to content

Commit 2690e97

Browse files
committed
[1.11>master] [MERGE #6155 @pleath] ChakraCore servicing update for June, 2019
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
2 parents e3b2498 + 3d6226c commit 2690e97

22 files changed

+427
-69
lines changed

lib/Backend/BackwardPass.cpp

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,8 @@ BackwardPass::ProcessLoop(BasicBlock * lastBlock)
16661666
{
16671667
Assert(loop->symsAssignedToInLoop == nullptr);
16681668
loop->symsAssignedToInLoop = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
1669+
Assert(loop->preservesNumberValue == nullptr);
1670+
loop->preservesNumberValue = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
16691671
}
16701672

16711673
FOREACH_BLOCK_BACKWARD_IN_RANGE_DEAD_OR_ALIVE(block, lastBlock, nullptr)
@@ -4486,7 +4488,10 @@ BackwardPass::ProcessNoImplicitCallDef(IR::Instr *const instr)
44864488
const bool transferArrayLengthSymUse = !!currentBlock->noImplicitCallArrayLengthSymUses->TestAndClear(dstSym->m_id);
44874489

44884490
IR::Opnd *const src = instr->GetSrc1();
4489-
if(!src || instr->GetSrc2())
4491+
4492+
// Stop attempting to transfer noImplicitCallUses symbol if the instr is not a transfer instr (based on the opcode's
4493+
// flags) or does not have the attributes to be a transfer instr (based on the existance of src and src2).
4494+
if(!src || (instr->GetSrc2() && !OpCodeAttr::NonIntTransfer(instr->m_opcode)))
44904495
{
44914496
return;
44924497
}
@@ -5176,16 +5181,24 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
51765181
return;
51775182
}
51785183

5184+
instr->GetDst()->AsIndirOpnd()->AllowConversion(true);
51795185
IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
51805186
if (!baseValueType.IsNotNativeArray() &&
5181-
(!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
51825187
!currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
51835188
!(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
51845189
{
51855190
// There is an upwards-exposed use of a native array. Since the array referenced by this instruction can be aliased,
51865191
// this instruction needs to bail out if it converts the native array even if this array specifically is not
51875192
// upwards-exposed.
5188-
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
5193+
if (!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar())
5194+
{
5195+
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
5196+
}
5197+
else
5198+
{
5199+
// We are assuming that array conversion is impossible here, so make sure we execute code that fails if conversion does happen.
5200+
instr->GetDst()->AsIndirOpnd()->AllowConversion(false);
5201+
}
51895202
}
51905203

51915204
if(baseOpnd->IsArrayRegOpnd() && baseOpnd->AsArrayRegOpnd()->EliminatedUpperBoundCheck())
@@ -7593,6 +7606,52 @@ BackwardPass::TrackFloatSymEquivalence(IR::Instr *const instr)
75937606
}
75947607
}
75957608

7609+
bool
7610+
BackwardPass::SymIsIntconstOrSelf(Sym *sym, IR::Opnd *opnd)
7611+
{
7612+
Assert(sym->IsStackSym());
7613+
if (!opnd->IsRegOpnd())
7614+
{
7615+
return false;
7616+
}
7617+
StackSym *opndSym = opnd->AsRegOpnd()->m_sym;
7618+
7619+
if (sym == opndSym)
7620+
{
7621+
return true;
7622+
}
7623+
7624+
if (!opndSym->IsSingleDef())
7625+
{
7626+
return false;
7627+
}
7628+
7629+
if (opndSym->GetInstrDef()->m_opcode == Js::OpCode::LdC_A_I4)
7630+
{
7631+
return true;
7632+
}
7633+
7634+
return false;
7635+
}
7636+
7637+
bool
7638+
BackwardPass::InstrPreservesNumberValues(IR::Instr *instr, Sym *defSym)
7639+
{
7640+
if (instr->m_opcode == Js::OpCode::Ld_A)
7641+
{
7642+
if (instr->GetSrc1()->IsRegOpnd())
7643+
{
7644+
IR::RegOpnd *src1 = instr->GetSrc1()->AsRegOpnd();
7645+
if (src1->m_sym->IsSingleDef())
7646+
{
7647+
instr = src1->m_sym->GetInstrDef();
7648+
}
7649+
}
7650+
}
7651+
return (OpCodeAttr::ProducesNumber(instr->m_opcode) ||
7652+
(instr->m_opcode == Js::OpCode::Add_A && this->SymIsIntconstOrSelf(defSym, instr->GetSrc1()) && this->SymIsIntconstOrSelf(defSym, instr->GetSrc2())));
7653+
}
7654+
75967655
bool
75977656
BackwardPass::ProcessDef(IR::Opnd * opnd)
75987657
{
@@ -7607,7 +7666,19 @@ BackwardPass::ProcessDef(IR::Opnd * opnd)
76077666
this->InvalidateCloneStrCandidate(opnd);
76087667
if ((tag == Js::BackwardPhase) && IsPrePass())
76097668
{
7610-
this->currentPrePassLoop->symsAssignedToInLoop->Set(sym->m_id);
7669+
bool firstDef = !this->currentPrePassLoop->symsAssignedToInLoop->TestAndSet(sym->m_id);
7670+
7671+
if (firstDef)
7672+
{
7673+
if (this->InstrPreservesNumberValues(this->currentInstr, sym))
7674+
{
7675+
this->currentPrePassLoop->preservesNumberValue->Set(sym->m_id);
7676+
}
7677+
}
7678+
else if (!this->InstrPreservesNumberValues(this->currentInstr, sym))
7679+
{
7680+
this->currentPrePassLoop->preservesNumberValue->Clear(sym->m_id);
7681+
}
76117682
}
76127683
}
76137684
}

lib/Backend/BackwardPass.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class BackwardPass
3636
bool ProcessDef(IR::Opnd * opnd);
3737
void ProcessTransfers(IR::Instr * instr);
3838
void ProcessFieldKills(IR::Instr * instr);
39+
bool SymIsIntconstOrSelf(Sym *sym, IR::Opnd *opnd);
40+
bool InstrPreservesNumberValues(IR::Instr *instr, Sym *defSym);
41+
3942
template<typename T> void ClearBucketsOnFieldKill(IR::Instr *instr, HashTable<T> *table);
4043
StackSym* ProcessByteCodeUsesDst(IR::ByteCodeUsesInstr * byteCodeUsesInstr);
4144
const BVSparse<JitArenaAllocator>* ProcessByteCodeUsesSrcs(IR::ByteCodeUsesInstr * byteCodeUsesInstr);

lib/Backend/FlowGraph.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ class Loop
587587
// cleanup in PreOptPeep in the pre-pass of a loop. For aggressively transferring
588588
// values in prepass, we need to know if a source sym was ever assigned to in a loop.
589589
BVSparse<JitArenaAllocator> *symsAssignedToInLoop;
590+
BVSparse<JitArenaAllocator> *preservesNumberValue;
590591

591592
BailOutInfo * bailOutInfo;
592593
IR::BailOutInstr * toPrimitiveSideEffectCheck;
@@ -732,6 +733,7 @@ class Loop
732733
symsAssignedToInLoop(nullptr),
733734
needImplicitCallBailoutChecksForJsArrayCheckHoist(false),
734735
inductionVariables(nullptr),
736+
preservesNumberValue(nullptr),
735737
dominatingLoopCountableBlock(nullptr),
736738
loopCount(nullptr),
737739
loopCountBasedBoundBaseSyms(nullptr),

lib/Backend/GlobOpt.cpp

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,7 +1254,7 @@ void GlobOpt::InsertValueCompensation(
12541254
{
12551255
IR::Instr *const newInstr =
12561256
IR::Instr::New(
1257-
Js::OpCode::Ld_I4,
1257+
Js::OpCode::Ld_A,
12581258
IR::RegOpnd::New(mergedHeadSegmentLengthSym, mergedHeadSegmentLengthSym->GetType(), func),
12591259
IR::RegOpnd::New(predecessorHeadSegmentLengthSym, predecessorHeadSegmentLengthSym->GetType(), func),
12601260
func);
@@ -2753,10 +2753,43 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
27532753
bool
27542754
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
27552755
{
2756-
return opnd && (
2757-
opnd->m_sym->m_isNotNumber ||
2758-
(inGlobOpt && !opnd->GetValueType().IsNumber() && !currentBlock->globOptData.IsTypeSpecialized(opnd->m_sym))
2759-
);
2756+
if (opnd == nullptr)
2757+
{
2758+
return false;
2759+
}
2760+
2761+
if (opnd->m_sym->m_isNotNumber)
2762+
{
2763+
return true;
2764+
}
2765+
2766+
if (!inGlobOpt)
2767+
{
2768+
return false;
2769+
}
2770+
2771+
if (opnd->GetValueType().IsNumber() || currentBlock->globOptData.IsTypeSpecialized(opnd->m_sym))
2772+
{
2773+
if (!this->IsLoopPrePass())
2774+
{
2775+
return false;
2776+
}
2777+
2778+
Value * opndValue = this->currentBlock->globOptData.FindValue(opnd->m_sym);
2779+
ValueInfo * opndValueInfo = opndValue ? opndValue->GetValueInfo() : nullptr;
2780+
if (!opndValueInfo)
2781+
{
2782+
return true;
2783+
}
2784+
if (this->prePassLoop->preservesNumberValue->Test(opnd->m_sym->m_id))
2785+
{
2786+
return false;
2787+
}
2788+
2789+
return !this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
2790+
}
2791+
2792+
return true;
27602793
}
27612794

27622795
bool
@@ -13064,6 +13097,26 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr)
1306413097
it.RemoveCurrent();
1306513098
}
1306613099
}
13100+
else if(kills.KillsObjectArraysWithNoMissingValues())
13101+
{
13102+
// Some operations may kill objects with arrays-with-no-missing-values in unlikely circumstances. Convert their value types to likely
13103+
// versions so that the checks have to be redone.
13104+
for(auto it = valuesToKillOnCalls->GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
13105+
{
13106+
Value *const value = it.CurrentValue();
13107+
ValueInfo *const valueInfo = value->GetValueInfo();
13108+
Assert(
13109+
valueInfo->IsArrayOrObjectWithArray() ||
13110+
valueInfo->IsOptimizedVirtualTypedArray() ||
13111+
valueInfo->IsOptimizedTypedArray() && valueInfo->AsArrayValueInfo()->HeadSegmentLengthSym());
13112+
if(!valueInfo->IsArrayOrObjectWithArray() || valueInfo->IsArray() || !valueInfo->HasNoMissingValues())
13113+
{
13114+
continue;
13115+
}
13116+
ChangeValueType(nullptr, value, valueInfo->Type().ToLikely(), false);
13117+
it.RemoveCurrent();
13118+
}
13119+
}
1306713120

1306813121
if(kills.KillsNativeArrays())
1306913122
{
@@ -13684,6 +13737,11 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
1368413737
{
1368513738
kills.SetKillsArrayLengths();
1368613739
}
13740+
13741+
if(doArrayMissingValueCheckHoist && !(useValueTypes && arrayValueType.IsArray()))
13742+
{
13743+
kills.SetKillsObjectArraysWithNoMissingValues();
13744+
}
1368713745
break;
1368813746
}
1368913747

lib/Backend/GlobOpt.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class JsArrayKills
313313
{
314314
bool killsAllArrays : 1;
315315
bool killsArraysWithNoMissingValues : 1;
316+
bool killsObjectArraysWithNoMissingValues : 1;
316317
bool killsNativeArrays : 1;
317318
bool killsArrayHeadSegments : 1;
318319
bool killsArrayHeadSegmentLengths : 1;
@@ -338,6 +339,9 @@ class JsArrayKills
338339
bool KillsArraysWithNoMissingValues() const { return killsArraysWithNoMissingValues; }
339340
void SetKillsArraysWithNoMissingValues() { killsArraysWithNoMissingValues = true; }
340341

342+
bool KillsObjectArraysWithNoMissingValues() const { return killsObjectArraysWithNoMissingValues; }
343+
void SetKillsObjectArraysWithNoMissingValues() { killsObjectArraysWithNoMissingValues = true; }
344+
341345
bool KillsNativeArrays() const { return killsNativeArrays; }
342346
void SetKillsNativeArrays() { killsNativeArrays = true; }
343347

@@ -769,6 +773,7 @@ class GlobOpt
769773
void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
770774
void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd** srcOpndPtr, Value *const srcVal);
771775
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const;
776+
772777
public:
773778
static bool IsTypeSpecPhaseOff(Func const * func);
774779
static bool DoAggressiveIntTypeSpec(Func const * func);
@@ -897,7 +902,7 @@ class GlobOpt
897902
void KillLiveFields(StackSym * stackSym, BVSparse<JitArenaAllocator> * bv);
898903
void KillLiveFields(PropertySym * propertySym, BVSparse<JitArenaAllocator> * bv);
899904
void KillLiveFields(BVSparse<JitArenaAllocator> *const fieldsToKill, BVSparse<JitArenaAllocator> *const bv) const;
900-
void KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
905+
void KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
901906
void KillAllFields(BVSparse<JitArenaAllocator> * bv);
902907
void SetAnyPropertyMayBeWrittenTo();
903908
void AddToPropertiesWrittenTo(Js::PropertyId propertyId);

lib/Backend/GlobOptFields.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void GlobOpt::KillLiveFields(BVSparse<JitArenaAllocator> *const fieldsToKill, BV
208208
}
209209

210210
void
211-
GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func)
211+
GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func)
212212
{
213213
IR::RegOpnd *indexOpnd = indirOpnd->GetIndexOpnd();
214214
// obj.x = 10;
@@ -240,6 +240,23 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> *
240240
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
241241
this->KillAllObjectTypes(bv);
242242
}
243+
else if ((!valueOpnd || valueOpnd->IsVar()) && this->objectTypeSyms != nullptr)
244+
{
245+
// If we wind up converting a native array, block final-type opt at this point, because we could evolve
246+
// to a type with the wrong type ID. Do this by noting that we may have evolved any type and so must
247+
// check it before evolving it further.
248+
IR::RegOpnd *baseOpnd = indirOpnd->GetBaseOpnd();
249+
Value * baseValue = baseOpnd ? this->currentBlock->globOptData.FindValue(baseOpnd->m_sym) : nullptr;
250+
ValueInfo * baseValueInfo = baseValue ? baseValue->GetValueInfo() : nullptr;
251+
if (!baseValueInfo || !baseValueInfo->IsNotNativeArray())
252+
{
253+
if (this->currentBlock->globOptData.maybeWrittenTypeSyms == nullptr)
254+
{
255+
this->currentBlock->globOptData.maybeWrittenTypeSyms = JitAnew(this->alloc, BVSparse<JitArenaAllocator>, this->alloc);
256+
}
257+
this->currentBlock->globOptData.maybeWrittenTypeSyms->Or(this->objectTypeSyms);
258+
}
259+
}
243260
}
244261
}
245262

@@ -332,7 +349,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
332349
case Js::OpCode::StElemI_A_Strict:
333350
Assert(dstOpnd != nullptr);
334351
KillLiveFields(this->lengthEquivBv, bv);
335-
KillLiveElems(dstOpnd->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
352+
KillLiveElems(dstOpnd->AsIndirOpnd(), instr->GetSrc1(), bv, inGlobOpt, instr->m_func);
336353
if (inGlobOpt)
337354
{
338355
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
@@ -342,7 +359,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
342359
case Js::OpCode::InitComputedProperty:
343360
case Js::OpCode::InitGetElemI:
344361
case Js::OpCode::InitSetElemI:
345-
KillLiveElems(dstOpnd->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
362+
KillLiveElems(dstOpnd->AsIndirOpnd(), instr->GetSrc1(), bv, inGlobOpt, instr->m_func);
346363
if (inGlobOpt)
347364
{
348365
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
@@ -352,7 +369,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
352369
case Js::OpCode::DeleteElemI_A:
353370
case Js::OpCode::DeleteElemIStrict_A:
354371
Assert(dstOpnd != nullptr);
355-
KillLiveElems(instr->GetSrc1()->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
372+
KillLiveElems(instr->GetSrc1()->AsIndirOpnd(), nullptr, bv, inGlobOpt, instr->m_func);
356373
break;
357374

358375
case Js::OpCode::DeleteFld:

lib/Backend/IR.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3428,7 +3428,14 @@ bool Instr::TransfersSrcValue()
34283428

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

3431-
return this->GetDst() != nullptr && this->GetSrc2() == nullptr && !OpCodeAttr::DoNotTransfer(this->m_opcode) && !this->CallsAccessor();
3431+
return
3432+
this->GetDst() != nullptr &&
3433+
3434+
// The lack of a Src2 does not always indicate that the instr is not a transfer instr (ex: StSlotChkUndecl).
3435+
(this->GetSrc2() == nullptr || OpCodeAttr::NonIntTransfer(this->m_opcode)) &&
3436+
3437+
!OpCodeAttr::DoNotTransfer(this->m_opcode) &&
3438+
!this->CallsAccessor();
34323439
}
34333440

34343441

0 commit comments

Comments
 (0)