Skip to content

Commit b5e4874

Browse files
committed
[1.11>master] [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 b278ab7 + 6b1250b commit b5e4874

31 files changed

+6321
-5569
lines changed

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)
@@ -416,6 +415,8 @@ BackwardPass::Optimize()
416415
candidateSymsRequiredToBeInt = &localCandidateSymsRequiredToBeInt;
417416
BVSparse<JitArenaAllocator> localCandidateSymsRequiredToBeLossyInt(tempAlloc);
418417
candidateSymsRequiredToBeLossyInt = &localCandidateSymsRequiredToBeLossyInt;
418+
BVSparse<JitArenaAllocator> localConsiderSymsAsRealUsesInNoImplicitCallUses(tempAlloc);
419+
considerSymsAsRealUsesInNoImplicitCallUses = &localConsiderSymsAsRealUsesInNoImplicitCallUses;
419420
intOverflowCurrentlyMattersInRange = true;
420421

421422
FloatSymEquivalenceMap localFloatSymEquivalenceMap(tempAlloc);
@@ -4022,7 +4023,7 @@ BackwardPass::ProcessBlock(BasicBlock * block)
40224023
block->loop->regAlloc.liveOnBackEdgeSyms = block->upwardExposedUses->CopyNew(this->func->m_alloc);
40234024
}
40244025

4025-
Assert(!considerSymAsRealUseInNoImplicitCallUses);
4026+
Assert(considerSymsAsRealUsesInNoImplicitCallUses->IsEmpty());
40264027

40274028
#if DBG_DUMP
40284029
TraceBlockUses(block, false);
@@ -4443,9 +4444,8 @@ BackwardPass::ProcessNoImplicitCallUses(IR::Instr *const instr)
44434444
{
44444445
IR::RegOpnd *const regSrc = src->AsRegOpnd();
44454446
sym = regSrc->m_sym;
4446-
if(considerSymAsRealUseInNoImplicitCallUses && considerSymAsRealUseInNoImplicitCallUses == sym)
4447+
if(considerSymsAsRealUsesInNoImplicitCallUses->TestAndClear(sym->m_id))
44474448
{
4448-
considerSymAsRealUseInNoImplicitCallUses = nullptr;
44494449
ProcessStackSymUse(sym->AsStackSym(), true);
44504450
}
44514451
if(regSrc->IsArrayRegOpnd())
@@ -4863,7 +4863,6 @@ BackwardPass::ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *c
48634863
// ProcessNoImplicitCallUses automatically marks JS array reg opnds and their corresponding syms as live. A typed
48644864
// array's head segment length sym also needs to be marked as live at its use in the NoImplicitCallUses instruction,
48654865
// but it is just in a reg opnd. Flag the opnd to have the sym be marked as live when that instruction is processed.
4866-
Assert(!considerSymAsRealUseInNoImplicitCallUses);
48674866
IR::Opnd *const use =
48684867
FindNoImplicitCallUse(
48694868
instr,
@@ -4874,7 +4873,7 @@ BackwardPass::ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *c
48744873
});
48754874
if(use)
48764875
{
4877-
considerSymAsRealUseInNoImplicitCallUses = arrayRegOpnd->HeadSegmentLengthSym();
4876+
considerSymsAsRealUsesInNoImplicitCallUses->Set(arrayRegOpnd->HeadSegmentLengthSym()->m_id);
48784877
}
48794878
}
48804879
}
@@ -6804,6 +6803,7 @@ BackwardPass::TrackIntUsage(IR::Instr *const instr)
68046803
case Js::OpCode::Coerce_Regex:
68056804
case Js::OpCode::Coerce_StrOrRegex:
68066805
case Js::OpCode::Conv_PrimStr:
6806+
case Js::OpCode::Conv_Prop:
68076807
// These instructions don't generate -0, and their behavior is the same for any src that is -0 or +0
68086808
SetNegativeZeroDoesNotMatterIfLastUse(instr->GetSrc1());
68096809
SetNegativeZeroDoesNotMatterIfLastUse(instr->GetSrc2());

lib/Backend/BackwardPass.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class BackwardPass
198198
BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterInRangeBySymId;
199199
BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeInt;
200200
BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeLossyInt;
201-
StackSym * considerSymAsRealUseInNoImplicitCallUses;
201+
BVSparse<JitArenaAllocator> * considerSymsAsRealUsesInNoImplicitCallUses;
202202
bool intOverflowCurrentlyMattersInRange;
203203
bool isCollectionPass;
204204
enum class CollectionPassSubPhase

lib/Backend/GlobOpt.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13374,6 +13374,37 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
1337413374
arraySrcOpt.Optimize();
1337513375
}
1337613376

13377+
void
13378+
GlobOpt::ProcessNoImplicitCallArrayUses(IR::RegOpnd * baseOpnd, IR::ArrayRegOpnd * baseArrayOpnd, IR::Instr * instr, bool isLikelyJsArray, bool useNoMissingValues)
13379+
{
13380+
if (isLikelyJsArray)
13381+
{
13382+
// Insert an instruction to indicate to the dead-store pass that implicit calls need to be kept disabled until this
13383+
// instruction. Operations other than LdElem, StElem and IsIn don't benefit much from arrays having no missing values,
13384+
// so no need to ensure that the array still has no missing values. For a particular array, if none of the accesses
13385+
// benefit much from the no-missing-values information, it may be beneficial to avoid checking for no missing
13386+
// values, especially in the case for a single array access, where the cost of the check could be relatively
13387+
// significant. An StElem has to do additional checks in the common path if the array may have missing values, and
13388+
// a StElem that operates on an array that has no missing values is more likely to keep the no-missing-values info
13389+
// on the array more precise, so it still benefits a little from the no-missing-values info.
13390+
this->CaptureNoImplicitCallUses(baseOpnd, isLikelyJsArray);
13391+
}
13392+
else if (baseArrayOpnd && baseArrayOpnd->HeadSegmentLengthSym())
13393+
{
13394+
// A typed array's array buffer may be transferred to a web worker as part of an implicit call, in which case the typed
13395+
// array's length is set to zero. Insert an instruction to indicate to the dead-store pass that implicit calls need to
13396+
// be disabled until this instruction.
13397+
IR::RegOpnd *const headSegmentLengthOpnd =
13398+
IR::RegOpnd::New(
13399+
baseArrayOpnd->HeadSegmentLengthSym(),
13400+
baseArrayOpnd->HeadSegmentLengthSym()->GetType(),
13401+
instr->m_func);
13402+
13403+
const IR::AutoReuseOpnd autoReuseHeadSegmentLengthOpnd(headSegmentLengthOpnd, instr->m_func);
13404+
this->CaptureNoImplicitCallUses(headSegmentLengthOpnd, false);
13405+
}
13406+
}
13407+
1337713408
void
1337813409
GlobOpt::OptStackArgLenAndConst(IR::Instr* instr, Value** src1Val)
1337913410
{

lib/Backend/GlobOpt.h

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

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

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

lib/Backend/GlobOptArrays.cpp

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,32 +1939,7 @@ void GlobOpt::ArraySrcOpt::Optimize()
19391939
baseArrayOpnd = nullptr;
19401940
}
19411941

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

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

lib/Backend/GlobOptFields.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse
224224
// - We check the type specialization status for the sym as well. For the purpose of doing kills, we can assume that
225225
// if type specialization happened, that fields don't need to be killed. Note that they may be killed in the next
226226
// pass based on the value.
227-
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt))
227+
bool isSafeToTransfer = true;
228+
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt, &isSafeToTransfer))
228229
{
229230
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
230231
SetAnyPropertyMayBeWrittenTo();
@@ -235,7 +236,7 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse
235236
ValueInfo * indexValueInfo = indexValue ? indexValue->GetValueInfo() : nullptr;
236237
int indexLowerBound = 0;
237238

238-
if (indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
239+
if (!isSafeToTransfer || indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
239240
{
240241
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
241242
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
@@ -2840,6 +2840,10 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
28402840
this->LowerConvPrimStr(instr);
28412841
break;
28422842

2843+
case Js::OpCode::Conv_Prop:
2844+
this->LowerConvPropertyKey(instr);
2845+
break;
2846+
28432847
case Js::OpCode::ClearAttributes:
28442848
this->LowerBinaryHelper(instr, IR::HelperOP_ClearAttributes);
28452849
break;
@@ -26090,6 +26094,12 @@ Lowerer::GenerateGetImmutableOrScriptUnreferencedString(IR::RegOpnd * strOpnd, I
2609026094
return dstOpnd;
2609126095
}
2609226096

26097+
void
26098+
Lowerer::LowerConvPropertyKey(IR::Instr* instr)
26099+
{
26100+
LowerConvStrCommon(IR::HelperOp_ConvPropertyKey, instr);
26101+
}
26102+
2609326103
void
2609426104
Lowerer::LowerConvStrCommon(IR::JnHelperMethod helper, IR::Instr * instr)
2609526105
{

lib/Backend/Lower.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,8 @@ class Lowerer
678678
void LowerConvPrimStr(IR::Instr * instr);
679679
void LowerConvStrCommon(IR::JnHelperMethod helper, IR::Instr * instr);
680680

681+
void LowerConvPropertyKey(IR::Instr* instr);
682+
681683
void GenerateRecyclerAlloc(IR::JnHelperMethod allocHelper, size_t allocSize, IR::RegOpnd* newObjDst, IR::Instr* insertionPointInstr, bool inOpHelper = false);
682684

683685
template <typename ArrayType>

lib/Jsrt/JsrtDebuggerObject.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,22 @@ Js::DynamicObject * JsrtDebuggerObjectBase::GetChildren(WeakArenaReference<Js::I
8585
if (resolvedObjectDisplay != nullptr)
8686
{
8787
JsrtDebuggerObjectBase* debuggerObject = JsrtDebuggerObjectProperty::Make(this->GetDebuggerObjectsManager(), objectDisplayWeakRef);
88-
Js::DynamicObject* object = debuggerObject->GetJSONObject(resolvedObject.scriptContext, /* forceSetValueProp */ false);
89-
Js::Var marshaledObj = Js::CrossSite::MarshalVar(scriptContext, object);
90-
if (resolvedObjectDisplay->IsFake())
88+
try
9189
{
92-
Js::JavascriptOperators::OP_SetElementI((Js::Var)debuggerOnlyPropertiesArray, Js::JavascriptNumber::ToVar(debuggerOnlyPropertiesArrayCount++, scriptContext), marshaledObj, scriptContext);
90+
Js::DynamicObject* object = debuggerObject->GetJSONObject(resolvedObject.scriptContext, /* forceSetValueProp */ false);
91+
Js::Var marshaledObj = Js::CrossSite::MarshalVar(scriptContext, object);
92+
if (resolvedObjectDisplay->IsFake())
93+
{
94+
Js::JavascriptOperators::OP_SetElementI((Js::Var)debuggerOnlyPropertiesArray, Js::JavascriptNumber::ToVar(debuggerOnlyPropertiesArrayCount++, scriptContext), marshaledObj, scriptContext);
95+
}
96+
else
97+
{
98+
Js::JavascriptOperators::OP_SetElementI((Js::Var)propertiesArray, Js::JavascriptNumber::ToVar(propertiesArrayCount++, scriptContext), marshaledObj, scriptContext);
99+
}
93100
}
94-
else
101+
catch (const Js::JavascriptException& err)
95102
{
96-
Js::JavascriptOperators::OP_SetElementI((Js::Var)propertiesArray, Js::JavascriptNumber::ToVar(propertiesArrayCount++, scriptContext), marshaledObj, scriptContext);
103+
err.GetAndClear(); // discard exception object
97104
}
98105
objectDisplayWeakRef->ReleaseStrongReference();
99106
objectDisplayWeakRef.Detach();
@@ -415,11 +422,18 @@ Js::DynamicObject * JsrtDebuggerStackFrame::GetLocalsObject(Js::ScriptContext* s
415422
{
416423
AutoPtr<WeakArenaReference<Js::IDiagObjectModelDisplay>> objectDisplayWeakRef(resolvedObject.GetObjectDisplay());
417424
JsrtDebuggerObjectBase* debuggerObject = JsrtDebuggerObjectScope::Make(debuggerObjectsManager, objectDisplayWeakRef, scopesCount);
418-
Js::DynamicObject* object = debuggerObject->GetJSONObject(resolvedObject.scriptContext, /* forceSetValueProp */ false);
419-
Assert(object != nullptr);
420-
Js::Var marshaledObj = Js::CrossSite::MarshalVar(scriptContext, object);
421-
Js::JavascriptOperators::OP_SetElementI((Js::Var)scopesArray, Js::JavascriptNumber::ToVar(scopesCount, scriptContext), marshaledObj, scriptContext);
422-
scopesCount++;
425+
try
426+
{
427+
Js::DynamicObject* object = debuggerObject->GetJSONObject(resolvedObject.scriptContext, /* forceSetValueProp */ false);
428+
Assert(object != nullptr);
429+
Js::Var marshaledObj = Js::CrossSite::MarshalVar(scriptContext, object);
430+
Js::JavascriptOperators::OP_SetElementI((Js::Var)scopesArray, Js::JavascriptNumber::ToVar(scopesCount, scriptContext), marshaledObj, scriptContext);
431+
scopesCount++;
432+
}
433+
catch (const Js::JavascriptException& err)
434+
{
435+
err.GetAndClear(); // discard exception object
436+
}
423437
objectDisplayWeakRef.Detach();
424438
}
425439
}
@@ -952,4 +966,4 @@ void JsrtDebugStackFrames::ClearFrameDictionary()
952966
this->framesDictionary->Clear();
953967
}
954968
}
955-
#endif
969+
#endif

0 commit comments

Comments
 (0)