Skip to content

Commit 3d6226c

Browse files
committed
[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 d797e3f + eabf77a commit 3d6226c

23 files changed

+430
-74
lines changed

Build/Common.Build.Default.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<PlatformToolset Condition="'$(BuildToolVersion)'=='12.0'">v120</PlatformToolset>
1818
<PlatformToolset Condition="'$(BuildToolVersion)'=='14.0'">v140</PlatformToolset>
1919
<PlatformToolset Condition="'$(BuildToolVersion)'=='15.0'">v141</PlatformToolset>
20+
<PlatformToolset Condition="'$(BuildToolVersion)'=='16.0'">v142</PlatformToolset>
2021
</PropertyGroup>
2122

2223
<!-- Default ChakraDevConfigDir -->

Build/NuGet/.pack-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.11.9
1+
1.11.10

lib/Backend/BackwardPass.cpp

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,8 @@ BackwardPass::ProcessLoop(BasicBlock * lastBlock)
16451645
{
16461646
Assert(loop->symsAssignedToInLoop == nullptr);
16471647
loop->symsAssignedToInLoop = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
1648+
Assert(loop->preservesNumberValue == nullptr);
1649+
loop->preservesNumberValue = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
16481650
}
16491651

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

43184320
IR::Opnd *const src = instr->GetSrc1();
4319-
if(!src || instr->GetSrc2())
4321+
4322+
// Stop attempting to transfer noImplicitCallUses symbol if the instr is not a transfer instr (based on the opcode's
4323+
// flags) or does not have the attributes to be a transfer instr (based on the existance of src and src2).
4324+
if(!src || (instr->GetSrc2() && !OpCodeAttr::NonIntTransfer(instr->m_opcode)))
43204325
{
43214326
return;
43224327
}
@@ -5004,16 +5009,24 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
50045009
return;
50055010
}
50065011

5012+
instr->GetDst()->AsIndirOpnd()->AllowConversion(true);
50075013
IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
50085014
if (!baseValueType.IsNotNativeArray() &&
5009-
(!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
50105015
!currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
50115016
!(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
50125017
{
50135018
// There is an upwards-exposed use of a native array. Since the array referenced by this instruction can be aliased,
50145019
// this instruction needs to bail out if it converts the native array even if this array specifically is not
50155020
// upwards-exposed.
5016-
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
5021+
if (!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar())
5022+
{
5023+
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
5024+
}
5025+
else
5026+
{
5027+
// We are assuming that array conversion is impossible here, so make sure we execute code that fails if conversion does happen.
5028+
instr->GetDst()->AsIndirOpnd()->AllowConversion(false);
5029+
}
50175030
}
50185031

50195032
if(baseOpnd->IsArrayRegOpnd() && baseOpnd->AsArrayRegOpnd()->EliminatedUpperBoundCheck())
@@ -7410,6 +7423,52 @@ BackwardPass::TrackFloatSymEquivalence(IR::Instr *const instr)
74107423
}
74117424
}
74127425

7426+
bool
7427+
BackwardPass::SymIsIntconstOrSelf(Sym *sym, IR::Opnd *opnd)
7428+
{
7429+
Assert(sym->IsStackSym());
7430+
if (!opnd->IsRegOpnd())
7431+
{
7432+
return false;
7433+
}
7434+
StackSym *opndSym = opnd->AsRegOpnd()->m_sym;
7435+
7436+
if (sym == opndSym)
7437+
{
7438+
return true;
7439+
}
7440+
7441+
if (!opndSym->IsSingleDef())
7442+
{
7443+
return false;
7444+
}
7445+
7446+
if (opndSym->GetInstrDef()->m_opcode == Js::OpCode::LdC_A_I4)
7447+
{
7448+
return true;
7449+
}
7450+
7451+
return false;
7452+
}
7453+
7454+
bool
7455+
BackwardPass::InstrPreservesNumberValues(IR::Instr *instr, Sym *defSym)
7456+
{
7457+
if (instr->m_opcode == Js::OpCode::Ld_A)
7458+
{
7459+
if (instr->GetSrc1()->IsRegOpnd())
7460+
{
7461+
IR::RegOpnd *src1 = instr->GetSrc1()->AsRegOpnd();
7462+
if (src1->m_sym->IsSingleDef())
7463+
{
7464+
instr = src1->m_sym->GetInstrDef();
7465+
}
7466+
}
7467+
}
7468+
return (OpCodeAttr::ProducesNumber(instr->m_opcode) ||
7469+
(instr->m_opcode == Js::OpCode::Add_A && this->SymIsIntconstOrSelf(defSym, instr->GetSrc1()) && this->SymIsIntconstOrSelf(defSym, instr->GetSrc2())));
7470+
}
7471+
74137472
bool
74147473
BackwardPass::ProcessDef(IR::Opnd * opnd)
74157474
{
@@ -7424,7 +7483,19 @@ BackwardPass::ProcessDef(IR::Opnd * opnd)
74247483
this->InvalidateCloneStrCandidate(opnd);
74257484
if ((tag == Js::BackwardPhase) && IsPrePass())
74267485
{
7427-
this->currentPrePassLoop->symsAssignedToInLoop->Set(sym->m_id);
7486+
bool firstDef = !this->currentPrePassLoop->symsAssignedToInLoop->TestAndSet(sym->m_id);
7487+
7488+
if (firstDef)
7489+
{
7490+
if (this->InstrPreservesNumberValues(this->currentInstr, sym))
7491+
{
7492+
this->currentPrePassLoop->preservesNumberValue->Set(sym->m_id);
7493+
}
7494+
}
7495+
else if (!this->InstrPreservesNumberValues(this->currentInstr, sym))
7496+
{
7497+
this->currentPrePassLoop->preservesNumberValue->Clear(sym->m_id);
7498+
}
74287499
}
74297500
}
74307501
}

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
@@ -588,6 +588,7 @@ class Loop
588588
// cleanup in PreOptPeep in the pre-pass of a loop. For aggressively transferring
589589
// values in prepass, we need to know if a source sym was ever assigned to in a loop.
590590
BVSparse<JitArenaAllocator> *symsAssignedToInLoop;
591+
BVSparse<JitArenaAllocator> *preservesNumberValue;
591592

592593
BailOutInfo * bailOutInfo;
593594
IR::BailOutInstr * toPrimitiveSideEffectCheck;
@@ -733,6 +734,7 @@ class Loop
733734
symsAssignedToInLoop(nullptr),
734735
needImplicitCallBailoutChecksForJsArrayCheckHoist(false),
735736
inductionVariables(nullptr),
737+
preservesNumberValue(nullptr),
736738
dominatingLoopCountableBlock(nullptr),
737739
loopCount(nullptr),
738740
loopCountBasedBoundBaseSyms(nullptr),

lib/Backend/GlobOpt.cpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ void GlobOpt::InsertValueCompensation(
12441244
{
12451245
IR::Instr *const newInstr =
12461246
IR::Instr::New(
1247-
Js::OpCode::Ld_I4,
1247+
Js::OpCode::Ld_A,
12481248
IR::RegOpnd::New(mergedHeadSegmentLengthSym, mergedHeadSegmentLengthSym->GetType(), func),
12491249
IR::RegOpnd::New(predecessorHeadSegmentLengthSym, predecessorHeadSegmentLengthSym->GetType(), func),
12501250
func);
@@ -2694,6 +2694,48 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
26942694
return instrNext;
26952695
}
26962696

2697+
bool
2698+
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
2699+
{
2700+
if (opnd == nullptr)
2701+
{
2702+
return false;
2703+
}
2704+
2705+
if (opnd->m_sym->m_isNotNumber)
2706+
{
2707+
return true;
2708+
}
2709+
2710+
if (!inGlobOpt)
2711+
{
2712+
return false;
2713+
}
2714+
2715+
if (opnd->GetValueType().IsNumber() || currentBlock->globOptData.IsTypeSpecialized(opnd->m_sym))
2716+
{
2717+
if (!this->IsLoopPrePass())
2718+
{
2719+
return false;
2720+
}
2721+
2722+
Value * opndValue = this->currentBlock->globOptData.FindValue(opnd->m_sym);
2723+
ValueInfo * opndValueInfo = opndValue ? opndValue->GetValueInfo() : nullptr;
2724+
if (!opndValueInfo)
2725+
{
2726+
return true;
2727+
}
2728+
if (this->prePassLoop->preservesNumberValue->Test(opnd->m_sym->m_id))
2729+
{
2730+
return false;
2731+
}
2732+
2733+
return !this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
2734+
}
2735+
2736+
return true;
2737+
}
2738+
26972739
bool
26982740
GlobOpt::OptTagChecks(IR::Instr *instr)
26992741
{
@@ -12827,6 +12869,26 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr)
1282712869
it.RemoveCurrent();
1282812870
}
1282912871
}
12872+
else if(kills.KillsObjectArraysWithNoMissingValues())
12873+
{
12874+
// Some operations may kill objects with arrays-with-no-missing-values in unlikely circumstances. Convert their value types to likely
12875+
// versions so that the checks have to be redone.
12876+
for(auto it = valuesToKillOnCalls->GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
12877+
{
12878+
Value *const value = it.CurrentValue();
12879+
ValueInfo *const valueInfo = value->GetValueInfo();
12880+
Assert(
12881+
valueInfo->IsArrayOrObjectWithArray() ||
12882+
valueInfo->IsOptimizedVirtualTypedArray() ||
12883+
valueInfo->IsOptimizedTypedArray() && valueInfo->AsArrayValueInfo()->HeadSegmentLengthSym());
12884+
if(!valueInfo->IsArrayOrObjectWithArray() || valueInfo->IsArray() || !valueInfo->HasNoMissingValues())
12885+
{
12886+
continue;
12887+
}
12888+
ChangeValueType(nullptr, value, valueInfo->Type().ToLikely(), false);
12889+
it.RemoveCurrent();
12890+
}
12891+
}
1283012892

1283112893
if(kills.KillsNativeArrays())
1283212894
{
@@ -13358,6 +13420,11 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
1335813420
{
1335913421
kills.SetKillsArrayLengths();
1336013422
}
13423+
13424+
if(doArrayMissingValueCheckHoist && !(useValueTypes && arrayValueType.IsArray()))
13425+
{
13426+
kills.SetKillsObjectArraysWithNoMissingValues();
13427+
}
1336113428
break;
1336213429
}
1336313430

lib/Backend/GlobOpt.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ class JsArrayKills
317317
{
318318
bool killsAllArrays : 1;
319319
bool killsArraysWithNoMissingValues : 1;
320+
bool killsObjectArraysWithNoMissingValues : 1;
320321
bool killsNativeArrays : 1;
321322
bool killsArrayHeadSegments : 1;
322323
bool killsArrayHeadSegmentLengths : 1;
@@ -342,6 +343,9 @@ class JsArrayKills
342343
bool KillsArraysWithNoMissingValues() const { return killsArraysWithNoMissingValues; }
343344
void SetKillsArraysWithNoMissingValues() { killsArraysWithNoMissingValues = true; }
344345

346+
bool KillsObjectArraysWithNoMissingValues() const { return killsObjectArraysWithNoMissingValues; }
347+
void SetKillsObjectArraysWithNoMissingValues() { killsObjectArraysWithNoMissingValues = true; }
348+
345349
bool KillsNativeArrays() const { return killsNativeArrays; }
346350
void SetKillsNativeArrays() { killsNativeArrays = true; }
347351

@@ -769,6 +773,8 @@ class GlobOpt
769773
const bool lossy = false, const bool forceInvariantHoisting = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
770774
void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
771775
void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd** srcOpndPtr, Value *const srcVal);
776+
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const;
777+
772778
public:
773779
static bool IsTypeSpecPhaseOff(Func const * func);
774780
static bool DoAggressiveIntTypeSpec(Func const * func);
@@ -891,7 +897,7 @@ class GlobOpt
891897
void KillLiveFields(StackSym * stackSym, BVSparse<JitArenaAllocator> * bv);
892898
void KillLiveFields(PropertySym * propertySym, BVSparse<JitArenaAllocator> * bv);
893899
void KillLiveFields(BVSparse<JitArenaAllocator> *const fieldsToKill, BVSparse<JitArenaAllocator> *const bv) const;
894-
void KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
900+
void KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse<JitArenaAllocator> * bv, bool inGlobOpt, Func *func);
895901
void KillAllFields(BVSparse<JitArenaAllocator> * bv);
896902
void SetAnyPropertyMayBeWrittenTo();
897903
void AddToPropertiesWrittenTo(Js::PropertyId propertyId);

lib/Backend/GlobOptFields.cpp

Lines changed: 22 additions & 12 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

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

@@ -340,7 +350,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
340350
case Js::OpCode::StElemI_A_Strict:
341351
Assert(dstOpnd != nullptr);
342352
KillLiveFields(this->lengthEquivBv, bv);
343-
KillLiveElems(dstOpnd->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
353+
KillLiveElems(dstOpnd->AsIndirOpnd(), instr->GetSrc1(), bv, inGlobOpt, instr->m_func);
344354
if (inGlobOpt)
345355
{
346356
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
@@ -350,7 +360,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
350360
case Js::OpCode::InitComputedProperty:
351361
case Js::OpCode::InitGetElemI:
352362
case Js::OpCode::InitSetElemI:
353-
KillLiveElems(dstOpnd->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
363+
KillLiveElems(dstOpnd->AsIndirOpnd(), instr->GetSrc1(), bv, inGlobOpt, instr->m_func);
354364
if (inGlobOpt)
355365
{
356366
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
@@ -360,7 +370,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
360370
case Js::OpCode::DeleteElemI_A:
361371
case Js::OpCode::DeleteElemIStrict_A:
362372
Assert(dstOpnd != nullptr);
363-
KillLiveElems(instr->GetSrc1()->AsIndirOpnd(), bv, inGlobOpt, instr->m_func);
373+
KillLiveElems(instr->GetSrc1()->AsIndirOpnd(), nullptr, bv, inGlobOpt, instr->m_func);
364374
break;
365375

366376
case Js::OpCode::DeleteFld:

lib/Backend/IR.cpp

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

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

3310-
return this->GetDst() != nullptr && this->GetSrc2() == nullptr && !OpCodeAttr::DoNotTransfer(this->m_opcode) && !this->CallsAccessor();
3310+
return
3311+
this->GetDst() != nullptr &&
3312+
3313+
// The lack of a Src2 does not always indicate that the instr is not a transfer instr (ex: StSlotChkUndecl).
3314+
(this->GetSrc2() == nullptr || OpCodeAttr::NonIntTransfer(this->m_opcode)) &&
3315+
3316+
!OpCodeAttr::DoNotTransfer(this->m_opcode) &&
3317+
!this->CallsAccessor();
33113318
}
33123319

33133320

0 commit comments

Comments
 (0)