Skip to content

Commit 6b1250b

Browse files
committed
[MERGE #6243 @wyrichte] ChakraCore servicing update for August, 2019
Merge pull request #6243 from wyrichte:gh_servicing_1908 This release addresses the following issues: CVE-2019-1197 CVE-2019-1141 CVE-2019-1196 CVE-2019-1139 CVE-2019-1131 CVE-2019-1195
2 parents 75162b7 + 450a349 commit 6b1250b

33 files changed

+888
-771
lines changed

Build/NuGet/.pack-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.11.11
1+
1.11.12

lib/Backend/BackwardPass.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
BackwardPass::BackwardPass(Func * func, GlobOpt * globOpt, Js::Phase tag)
1111
: func(func), globOpt(globOpt), tag(tag), currentPrePassLoop(nullptr), tempAlloc(nullptr),
1212
preOpBailOutInstrToProcess(nullptr),
13-
considerSymAsRealUseInNoImplicitCallUses(nullptr),
1413
isCollectionPass(false), currentRegion(nullptr),
1514
collectionPassSubPhase(CollectionPassSubPhase::None),
1615
isLoopPrepass(false)
@@ -412,6 +411,8 @@ BackwardPass::Optimize()
412411
candidateSymsRequiredToBeInt = &localCandidateSymsRequiredToBeInt;
413412
BVSparse<JitArenaAllocator> localCandidateSymsRequiredToBeLossyInt(tempAlloc);
414413
candidateSymsRequiredToBeLossyInt = &localCandidateSymsRequiredToBeLossyInt;
414+
BVSparse<JitArenaAllocator> localConsiderSymsAsRealUsesInNoImplicitCallUses(tempAlloc);
415+
considerSymsAsRealUsesInNoImplicitCallUses = &localConsiderSymsAsRealUsesInNoImplicitCallUses;
415416
intOverflowCurrentlyMattersInRange = true;
416417

417418
FloatSymEquivalenceMap localFloatSymEquivalenceMap(tempAlloc);
@@ -3755,7 +3756,7 @@ BackwardPass::ProcessBlock(BasicBlock * block)
37553756
block->loop->regAlloc.liveOnBackEdgeSyms = block->upwardExposedUses->CopyNew(this->func->m_alloc);
37563757
}
37573758

3758-
Assert(!considerSymAsRealUseInNoImplicitCallUses);
3759+
Assert(considerSymsAsRealUsesInNoImplicitCallUses->IsEmpty());
37593760

37603761
#if DBG_DUMP
37613762
TraceBlockUses(block, false);
@@ -4228,9 +4229,8 @@ BackwardPass::ProcessNoImplicitCallUses(IR::Instr *const instr)
42284229
{
42294230
IR::RegOpnd *const regSrc = src->AsRegOpnd();
42304231
sym = regSrc->m_sym;
4231-
if(considerSymAsRealUseInNoImplicitCallUses && considerSymAsRealUseInNoImplicitCallUses == sym)
4232+
if(considerSymsAsRealUsesInNoImplicitCallUses->TestAndClear(sym->m_id))
42324233
{
4233-
considerSymAsRealUseInNoImplicitCallUses = nullptr;
42344234
ProcessStackSymUse(sym->AsStackSym(), true);
42354235
}
42364236
if(regSrc->IsArrayRegOpnd())
@@ -4648,7 +4648,6 @@ BackwardPass::ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *c
46484648
// ProcessNoImplicitCallUses automatically marks JS array reg opnds and their corresponding syms as live. A typed
46494649
// array's head segment length sym also needs to be marked as live at its use in the NoImplicitCallUses instruction,
46504650
// but it is just in a reg opnd. Flag the opnd to have the sym be marked as live when that instruction is processed.
4651-
Assert(!considerSymAsRealUseInNoImplicitCallUses);
46524651
IR::Opnd *const use =
46534652
FindNoImplicitCallUse(
46544653
instr,
@@ -4659,7 +4658,7 @@ BackwardPass::ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *c
46594658
});
46604659
if(use)
46614660
{
4662-
considerSymAsRealUseInNoImplicitCallUses = arrayRegOpnd->HeadSegmentLengthSym();
4661+
considerSymsAsRealUsesInNoImplicitCallUses->Set(arrayRegOpnd->HeadSegmentLengthSym()->m_id);
46634662
}
46644663
}
46654664
}
@@ -6555,6 +6554,7 @@ BackwardPass::TrackIntUsage(IR::Instr *const instr)
65556554
case Js::OpCode::Coerce_Regex:
65566555
case Js::OpCode::Coerce_StrOrRegex:
65576556
case Js::OpCode::Conv_PrimStr:
6557+
case Js::OpCode::Conv_Prop:
65586558
// These instructions don't generate -0, and their behavior is the same for any src that is -0 or +0
65596559
SetNegativeZeroDoesNotMatterIfLastUse(instr->GetSrc1());
65606560
SetNegativeZeroDoesNotMatterIfLastUse(instr->GetSrc2());

lib/Backend/BackwardPass.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class BackwardPass
191191
BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterInRangeBySymId;
192192
BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeInt;
193193
BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeLossyInt;
194-
StackSym * considerSymAsRealUseInNoImplicitCallUses;
194+
BVSparse<JitArenaAllocator> * considerSymsAsRealUsesInNoImplicitCallUses;
195195
bool intOverflowCurrentlyMattersInRange;
196196
bool isCollectionPass;
197197
enum class CollectionPassSubPhase

lib/Backend/GlobOpt.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,7 +2695,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
26952695
}
26962696

26972697
bool
2698-
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
2698+
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt, bool *isSafeToTransferInPrepass /*=nullptr*/) const
26992699
{
27002700
if (opnd == nullptr)
27012701
{
@@ -2725,12 +2725,18 @@ GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
27252725
{
27262726
return true;
27272727
}
2728+
2729+
bool isSafeToTransfer = this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
2730+
if (isSafeToTransferInPrepass != nullptr)
2731+
{
2732+
*isSafeToTransferInPrepass = isSafeToTransfer;
2733+
}
27282734
if (this->prePassLoop->preservesNumberValue->Test(opnd->m_sym->m_id))
27292735
{
27302736
return false;
27312737
}
27322738

2733-
return !this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
2739+
return !isSafeToTransfer;
27342740
}
27352741

27362742
return true;
@@ -13143,6 +13149,37 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
1314313149
arraySrcOpt.Optimize();
1314413150
}
1314513151

13152+
void
13153+
GlobOpt::ProcessNoImplicitCallArrayUses(IR::RegOpnd * baseOpnd, IR::ArrayRegOpnd * baseArrayOpnd, IR::Instr * instr, bool isLikelyJsArray, bool useNoMissingValues)
13154+
{
13155+
if (isLikelyJsArray)
13156+
{
13157+
// Insert an instruction to indicate to the dead-store pass that implicit calls need to be kept disabled until this
13158+
// instruction. Operations other than LdElem, StElem and IsIn don't benefit much from arrays having no missing values,
13159+
// so no need to ensure that the array still has no missing values. For a particular array, if none of the accesses
13160+
// benefit much from the no-missing-values information, it may be beneficial to avoid checking for no missing
13161+
// values, especially in the case for a single array access, where the cost of the check could be relatively
13162+
// significant. An StElem has to do additional checks in the common path if the array may have missing values, and
13163+
// a StElem that operates on an array that has no missing values is more likely to keep the no-missing-values info
13164+
// on the array more precise, so it still benefits a little from the no-missing-values info.
13165+
this->CaptureNoImplicitCallUses(baseOpnd, isLikelyJsArray);
13166+
}
13167+
else if (baseArrayOpnd && baseArrayOpnd->HeadSegmentLengthSym())
13168+
{
13169+
// A typed array's array buffer may be transferred to a web worker as part of an implicit call, in which case the typed
13170+
// array's length is set to zero. Insert an instruction to indicate to the dead-store pass that implicit calls need to
13171+
// be disabled until this instruction.
13172+
IR::RegOpnd *const headSegmentLengthOpnd =
13173+
IR::RegOpnd::New(
13174+
baseArrayOpnd->HeadSegmentLengthSym(),
13175+
baseArrayOpnd->HeadSegmentLengthSym()->GetType(),
13176+
instr->m_func);
13177+
13178+
const IR::AutoReuseOpnd autoReuseHeadSegmentLengthOpnd(headSegmentLengthOpnd, instr->m_func);
13179+
this->CaptureNoImplicitCallUses(headSegmentLengthOpnd, false);
13180+
}
13181+
}
13182+
1314613183
void
1314713184
GlobOpt::CaptureNoImplicitCallUses(
1314813185
IR::Opnd *opnd,
@@ -13464,6 +13501,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
1346413501
case IR::HelperArray_Splice:
1346513502
case IR::HelperArray_Unshift:
1346613503
case IR::HelperArray_Concat:
13504+
case IR::HelperArray_Slice:
1346713505
kills.SetKillsArrayHeadSegments();
1346813506
kills.SetKillsArrayHeadSegmentLengths();
1346913507
break;
@@ -17031,11 +17069,27 @@ GlobOpt::EmitMemop(Loop * loop, LoopCount *loopCount, const MemOpEmitData* emitD
1703117069
}
1703217070
#endif
1703317071

17072+
Assert(noImplicitCallUsesToInsert->Count() == 0);
17073+
bool isLikelyJsArray;
17074+
if (emitData->stElemInstr->GetDst()->IsIndirOpnd())
17075+
{
17076+
baseOpnd = emitData->stElemInstr->GetDst()->AsIndirOpnd()->GetBaseOpnd();
17077+
isLikelyJsArray = baseOpnd->GetValueType().IsLikelyArrayOrObjectWithArray();
17078+
ProcessNoImplicitCallArrayUses(baseOpnd, baseOpnd->IsArrayRegOpnd() ? baseOpnd->AsArrayRegOpnd() : nullptr, emitData->stElemInstr, isLikelyJsArray, true);
17079+
}
1703417080
RemoveMemOpSrcInstr(memopInstr, emitData->stElemInstr, emitData->block);
1703517081
if (!isMemset)
1703617082
{
17083+
if (((MemCopyEmitData*)emitData)->ldElemInstr->GetSrc1()->IsIndirOpnd())
17084+
{
17085+
baseOpnd = ((MemCopyEmitData*)emitData)->ldElemInstr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd();
17086+
isLikelyJsArray = baseOpnd->GetValueType().IsLikelyArrayOrObjectWithArray();
17087+
ProcessNoImplicitCallArrayUses(baseOpnd, baseOpnd->IsArrayRegOpnd() ? baseOpnd->AsArrayRegOpnd() : nullptr, emitData->stElemInstr, isLikelyJsArray, true);
17088+
}
1703717089
RemoveMemOpSrcInstr(memopInstr, ((MemCopyEmitData*)emitData)->ldElemInstr, emitData->block);
1703817090
}
17091+
InsertNoImplicitCallUses(memopInstr);
17092+
noImplicitCallUsesToInsert->Clear();
1703917093
}
1704017094

1704117095
bool

lib/Backend/GlobOpt.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ class GlobOpt
721721
private:
722722
void CaptureNoImplicitCallUses(IR::Opnd *opnd, const bool usesNoMissingValuesInfo, IR::Instr *const includeCurrentInstr = nullptr);
723723
void InsertNoImplicitCallUses(IR::Instr *const instr);
724+
void ProcessNoImplicitCallArrayUses(IR::RegOpnd * baseOpnd, IR::ArrayRegOpnd * baseArrayOpnd, IR::Instr * instr, bool isLikelyJsArray, bool useNoMissingValues);
724725
void PrepareLoopArrayCheckHoist();
725726

726727
public:
@@ -773,7 +774,7 @@ class GlobOpt
773774
const bool lossy = false, const bool forceInvariantHoisting = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
774775
void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
775776
void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd** srcOpndPtr, Value *const srcVal);
776-
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const;
777+
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt, bool *isSafeToTransferInPrepass = nullptr) const;
777778

778779
public:
779780
static bool IsTypeSpecPhaseOff(Func const * func);

lib/Backend/GlobOptArrays.cpp

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,32 +1929,7 @@ void GlobOpt::ArraySrcOpt::Optimize()
19291929
baseArrayOpnd = nullptr;
19301930
}
19311931

1932-
if (isLikelyJsArray)
1933-
{
1934-
// Insert an instruction to indicate to the dead-store pass that implicit calls need to be kept disabled until this
1935-
// instruction. Operations other than LdElem, StElem and IsIn don't benefit much from arrays having no missing values,
1936-
// so no need to ensure that the array still has no missing values. For a particular array, if none of the accesses
1937-
// benefit much from the no-missing-values information, it may be beneficial to avoid checking for no missing
1938-
// values, especially in the case for a single array access, where the cost of the check could be relatively
1939-
// significant. An StElem has to do additional checks in the common path if the array may have missing values, and
1940-
// a StElem that operates on an array that has no missing values is more likely to keep the no-missing-values info
1941-
// on the array more precise, so it still benefits a little from the no-missing-values info.
1942-
globOpt->CaptureNoImplicitCallUses(baseOpnd, isLoad || isStore || instr->m_opcode == Js::OpCode::IsIn);
1943-
}
1944-
else if (baseArrayOpnd && baseArrayOpnd->HeadSegmentLengthSym())
1945-
{
1946-
// A typed array's array buffer may be transferred to a web worker as part of an implicit call, in which case the typed
1947-
// array's length is set to zero. Insert an instruction to indicate to the dead-store pass that implicit calls need to
1948-
// be disabled until this instruction.
1949-
IR::RegOpnd *const headSegmentLengthOpnd =
1950-
IR::RegOpnd::New(
1951-
baseArrayOpnd->HeadSegmentLengthSym(),
1952-
baseArrayOpnd->HeadSegmentLengthSym()->GetType(),
1953-
instr->m_func);
1954-
1955-
const IR::AutoReuseOpnd autoReuseHeadSegmentLengthOpnd(headSegmentLengthOpnd, instr->m_func);
1956-
globOpt->CaptureNoImplicitCallUses(headSegmentLengthOpnd, false);
1957-
}
1932+
globOpt->ProcessNoImplicitCallArrayUses(baseOpnd, baseArrayOpnd, instr, isLikelyJsArray, isLoad || isStore || instr->m_opcode == Js::OpCode::IsIn);
19581933

19591934
const auto OnEliminated = [&](const Js::Phase phase, const char *const eliminatedLoad)
19601935
{

lib/Backend/GlobOptFields.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse
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() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt))
228+
bool isSafeToTransfer = true;
229+
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt, &isSafeToTransfer))
229230
{
230231
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
231232
SetAnyPropertyMayBeWrittenTo();
@@ -236,7 +237,7 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse
236237
ValueInfo * indexValueInfo = indexValue ? indexValue->GetValueInfo() : nullptr;
237238
int indexLowerBound = 0;
238239

239-
if (indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
240+
if (!isSafeToTransfer || indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
240241
{
241242
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
242243
this->KillAllObjectTypes(bv);
@@ -517,6 +518,18 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
517518
}
518519
break;
519520

521+
case IR::JnHelperMethod::HelperArray_Slice:
522+
case IR::JnHelperMethod::HelperArray_Concat:
523+
if (inGlobOpt && this->objectTypeSyms)
524+
{
525+
if (this->currentBlock->globOptData.maybeWrittenTypeSyms == nullptr)
526+
{
527+
this->currentBlock->globOptData.maybeWrittenTypeSyms = JitAnew(this->alloc, BVSparse<JitArenaAllocator>, this->alloc);
528+
}
529+
this->currentBlock->globOptData.maybeWrittenTypeSyms->Or(this->objectTypeSyms);
530+
}
531+
break;
532+
520533
case IR::JnHelperMethod::HelperRegExp_Exec:
521534
case IR::JnHelperMethod::HelperRegExp_ExecResultNotUsed:
522535
case IR::JnHelperMethod::HelperRegExp_ExecResultUsed:

lib/Backend/GlobOptIntBounds.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,13 +1278,20 @@ GlobOpt::InvalidateInductionVariables(IR::Instr * instr)
12781278
}
12791279

12801280
// If this is an induction variable, then treat it the way the prepass would have if it had seen
1281-
// the assignment and the resulting change to the value number, and mark it as indeterminate.
1281+
// the assignment and the resulting change to the value number, and mark induction variables
1282+
// for the loop as indeterminate.
1283+
// We need to invalidate all induction variables for the loop, because we might have used the
1284+
// invalidated induction variable to calculate the loopCount, and this now invalid loopCount
1285+
// also impacts bound checks for secondary induction variables
12821286
for (Loop * loop = this->currentBlock->loop; loop; loop = loop->parent)
12831287
{
1284-
InductionVariable *iv = nullptr;
1285-
if (loop->inductionVariables && loop->inductionVariables->TryGetReference(dstSym->m_id, &iv))
1288+
if (loop->inductionVariables && loop->inductionVariables->ContainsKey(dstSym->m_id))
12861289
{
1287-
iv->SetChangeIsIndeterminate();
1290+
for (auto it = loop->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
1291+
{
1292+
InductionVariable& inductionVariable = it.CurrentValueReference();
1293+
inductionVariable.SetChangeIsIndeterminate();
1294+
}
12881295
}
12891296
}
12901297
}

lib/Backend/JnHelperMethodList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ HELPERCALL_MATH(Op_MaxInAnArray, Js::JavascriptMath::MaxInAnArray, AttrCanThrow)
134134
HELPERCALL_MATH(Op_MinInAnArray, Js::JavascriptMath::MinInAnArray, AttrCanThrow)
135135

136136
HELPERCALLCHK(Op_ConvString, Js::JavascriptConversion::ToString, AttrCanThrow)
137+
HELPERCALLCHK(Op_ConvPropertyKey, Js::JavascriptOperators::OP_ToPropertyKey, AttrCanThrow)
137138
HELPERCALLCHK(Op_CoerseString, Js::JavascriptConversion::CoerseString, AttrCanThrow)
138139
HELPERCALLCHK(Op_CoerseRegex, (Js::JavascriptRegExp* (*) (Js::Var aValue, Js::Var options, Js::ScriptContext *scriptContext))Js::JavascriptRegExp::CreateRegEx, AttrCanThrow)
139140

lib/Backend/Lower.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,6 +2826,10 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
28262826
this->LowerConvPrimStr(instr);
28272827
break;
28282828

2829+
case Js::OpCode::Conv_Prop:
2830+
this->LowerConvPropertyKey(instr);
2831+
break;
2832+
28292833
case Js::OpCode::ClearAttributes:
28302834
this->LowerBinaryHelper(instr, IR::HelperOP_ClearAttributes);
28312835
break;
@@ -25474,6 +25478,12 @@ Lowerer::GenerateGetImmutableOrScriptUnreferencedString(IR::RegOpnd * strOpnd, I
2547425478
return dstOpnd;
2547525479
}
2547625480

25481+
void
25482+
Lowerer::LowerConvPropertyKey(IR::Instr* instr)
25483+
{
25484+
LowerConvStrCommon(IR::HelperOp_ConvPropertyKey, instr);
25485+
}
25486+
2547725487
void
2547825488
Lowerer::LowerConvStrCommon(IR::JnHelperMethod helper, IR::Instr * instr)
2547925489
{

0 commit comments

Comments
 (0)