Skip to content

Commit 1c75087

Browse files
committed
[1.11>master] [MERGE #6122 @MikeHolman] May 2019 Security Update
Merge pull request #6122 from pr/MikeHolman/servicing/1905 May 2019 Security Update that addresses the following issues in ChakraCore: CVE-2019-0911 CVE-2019-0912 CVE-2019-0913 CVE-2019-0914 CVE-2019-0915 CVE-2019-0916 CVE-2019-0917 CVE-2019-0922 CVE-2019-0923 CVE-2019-0924 CVE-2019-0925 CVE-2019-0927 CVE-2019-0933 CVE-2019-0937
2 parents 503294e + d797e3f commit 1c75087

16 files changed

+181
-35
lines changed

lib/Backend/BackwardPass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4847,7 +4847,7 @@ BackwardPass::ProcessNewScObject(IR::Instr* instr)
48474847

48484848
// The instruction could have a lazy bailout associated with it, which might get cleared
48494849
// later, so we make sure that we only process instructions with the right bailout kind.
4850-
if (instr->HasBailOutInfo() && instr->GetBailOutKind() == IR::BailOutFailedCtorGuardCheck)
4850+
if (instr->HasBailOutInfo() && instr->GetBailOutKindNoBits() == IR::BailOutFailedCtorGuardCheck)
48514851
{
48524852
Assert(instr->IsProfiledInstr());
48534853
Assert(instr->GetDst()->IsRegOpnd());

lib/Backend/GlobOpt.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13514,6 +13514,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
1351413514
const bool useValueTypes = !IsLoopPrePass(); // Source value types are not guaranteed to be correct in a loop prepass
1351513515
switch(instr->m_opcode)
1351613516
{
13517+
case Js::OpCode::StElemC:
1351713518
case Js::OpCode::StElemI_A:
1351813519
case Js::OpCode::StElemI_A_Strict:
1351913520
{
@@ -13564,8 +13565,13 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
1356413565
}
1356513566
break;
1356613567

13568+
case Js::OpCode::ConsoleScopedStFld:
13569+
case Js::OpCode::ConsoleScopedStFldStrict:
13570+
case Js::OpCode::ScopedStFld:
13571+
case Js::OpCode::ScopedStFldStrict:
1356713572
case Js::OpCode::StFld:
1356813573
case Js::OpCode::StFldStrict:
13574+
case Js::OpCode::StSuperFld:
1356913575
{
1357013576
Assert(instr->GetDst());
1357113577

@@ -13777,6 +13783,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
1377713783
break;
1377813784

1377913785
case Js::OpCode::NewScObjectNoCtor:
13786+
case Js::OpCode::NewScObjectNoCtorFull:
1378013787
if(doNativeArrayTypeSpec)
1378113788
{
1378213789
// Class/object construction can make something a prototype

lib/Backend/GlobOptArrays.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1746,7 +1746,14 @@ void GlobOpt::ArraySrcOpt::Optimize()
17461746
{
17471747
if (newBaseValueType != baseValueType)
17481748
{
1749-
UpdateValue(nullptr, nullptr, nullptr);
1749+
if (globOpt->IsSafeToTransferInPrePass(baseOpnd, baseValue))
1750+
{
1751+
UpdateValue(nullptr, nullptr, nullptr);
1752+
}
1753+
else if (isLikelyJsArray && globOpt->IsOperationThatLikelyKillsJsArraysWithNoMissingValues(instr) && baseValueInfo->HasNoMissingValues())
1754+
{
1755+
globOpt->ChangeValueType(nullptr, baseValue, baseValueInfo->Type().SetHasNoMissingValues(false), true);
1756+
}
17501757
}
17511758

17521759
// For javascript arrays and objects with javascript arrays:

lib/Backend/GlobOptBailOut.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,14 @@ GlobOpt::MayNeedBailOnImplicitCall(IR::Instr const * instr, Value const * src1Va
14991499
);
15001500
}
15011501

1502+
case Js::OpCode::NewScObjectNoCtor:
1503+
if (instr->HasBailOutInfo() && (instr->GetBailOutKind() & ~IR::BailOutKindBits) == IR::BailOutFailedCtorGuardCheck)
1504+
{
1505+
// No helper call with this bailout.
1506+
return false;
1507+
}
1508+
break;
1509+
15021510
default:
15031511
break;
15041512
}

lib/Backend/GlobOptExpr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,20 +814,28 @@ GlobOpt::ProcessArrayValueKills(IR::Instr *instr)
814814
{
815815
switch (instr->m_opcode)
816816
{
817+
case Js::OpCode::StElemC:
817818
case Js::OpCode::StElemI_A:
818819
case Js::OpCode::StElemI_A_Strict:
819820
case Js::OpCode::DeleteElemI_A:
820821
case Js::OpCode::DeleteElemIStrict_A:
822+
case Js::OpCode::ConsoleScopedStFld:
823+
case Js::OpCode::ConsoleScopedStFldStrict:
824+
case Js::OpCode::ScopedStFld:
825+
case Js::OpCode::ScopedStFldStrict:
821826
case Js::OpCode::StFld:
822827
case Js::OpCode::StRootFld:
823828
case Js::OpCode::StFldStrict:
824829
case Js::OpCode::StRootFldStrict:
830+
case Js::OpCode::StSuperFld:
825831
case Js::OpCode::StSlot:
826832
case Js::OpCode::StSlotChkUndecl:
827833
case Js::OpCode::DeleteFld:
828834
case Js::OpCode::DeleteRootFld:
829835
case Js::OpCode::DeleteFldStrict:
830836
case Js::OpCode::DeleteRootFldStrict:
837+
case Js::OpCode::ScopedDeleteFld:
838+
case Js::OpCode::ScopedDeleteFldStrict:
831839
case Js::OpCode::StArrViewElem:
832840
// These array helpers may change A.length (and A[i] could be A.length)...
833841
case Js::OpCode::InlineArrayPush:

lib/Backend/GlobOptFields.cpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
327327
IR::JnHelperMethod fnHelper;
328328
switch(instr->m_opcode)
329329
{
330+
case Js::OpCode::StElemC:
330331
case Js::OpCode::StElemI_A:
331332
case Js::OpCode::StElemI_A_Strict:
332333
Assert(dstOpnd != nullptr);
@@ -358,6 +359,8 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
358359
case Js::OpCode::DeleteRootFld:
359360
case Js::OpCode::DeleteFldStrict:
360361
case Js::OpCode::DeleteRootFldStrict:
362+
case Js::OpCode::ScopedDeleteFld:
363+
case Js::OpCode::ScopedDeleteFldStrict:
361364
sym = instr->GetSrc1()->AsSymOpnd()->m_sym;
362365
KillLiveFields(sym->AsPropertySym(), bv);
363366
if (inGlobOpt)
@@ -379,13 +382,36 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
379382
this->KillAllObjectTypes(bv);
380383
}
381384
break;
385+
386+
case Js::OpCode::ConsoleScopedStFld:
387+
case Js::OpCode::ConsoleScopedStFldStrict:
388+
case Js::OpCode::ScopedStFld:
389+
case Js::OpCode::ScopedStFldStrict:
390+
// This is already taken care of for FastFld opcodes
391+
392+
if (inGlobOpt)
393+
{
394+
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
395+
}
396+
397+
// fall through
398+
382399
case Js::OpCode::InitFld:
400+
case Js::OpCode::InitConstFld:
401+
case Js::OpCode::InitLetFld:
402+
case Js::OpCode::InitRootFld:
403+
case Js::OpCode::InitRootConstFld:
404+
case Js::OpCode::InitRootLetFld:
405+
#if !FLOATVAR
406+
case Js::OpCode::StSlotBoxTemp:
407+
#endif
383408
case Js::OpCode::StFld:
384409
case Js::OpCode::StRootFld:
385410
case Js::OpCode::StFldStrict:
386411
case Js::OpCode::StRootFldStrict:
387412
case Js::OpCode::StSlot:
388413
case Js::OpCode::StSlotChkUndecl:
414+
case Js::OpCode::StSuperFld:
389415
Assert(dstOpnd != nullptr);
390416
sym = dstOpnd->AsSymOpnd()->m_sym;
391417
if (inGlobOpt)
@@ -407,11 +433,19 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
407433

408434
case Js::OpCode::InlineArrayPush:
409435
case Js::OpCode::InlineArrayPop:
410-
KillLiveFields(this->lengthEquivBv, bv);
411-
if (inGlobOpt)
436+
if(instr->m_func->GetThisOrParentInlinerHasArguments())
412437
{
413-
// Deleting an item, or pushing a property to a non-array, may change object layout
414-
KillAllObjectTypes(bv);
438+
this->KillAllFields(bv);
439+
this->SetAnyPropertyMayBeWrittenTo();
440+
}
441+
else
442+
{
443+
KillLiveFields(this->lengthEquivBv, bv);
444+
if (inGlobOpt)
445+
{
446+
// Deleting an item, or pushing a property to a non-array, may change object layout
447+
KillAllObjectTypes(bv);
448+
}
415449
}
416450
break;
417451

@@ -436,14 +470,23 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
436470
// Kill length field for built-ins that can update it.
437471
if (nullptr != this->lengthEquivBv)
438472
{
439-
KillLiveFields(this->lengthEquivBv, bv);
473+
// If has arguments, all fields are killed in fall through
474+
if (!instr->m_func->GetThisOrParentInlinerHasArguments())
475+
{
476+
KillLiveFields(this->lengthEquivBv, bv);
477+
}
440478
}
441479
// fall through
442480

443481
case IR::JnHelperMethod::HelperArray_Reverse:
444-
// Deleting an item may change object layout
445-
if (inGlobOpt)
482+
if (instr->m_func->GetThisOrParentInlinerHasArguments())
483+
{
484+
this->KillAllFields(bv);
485+
this->SetAnyPropertyMayBeWrittenTo();
486+
}
487+
else if (inGlobOpt)
446488
{
489+
// Deleting an item may change object layout
447490
KillAllObjectTypes(bv);
448491
}
449492
break;
@@ -484,6 +527,7 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
484527
case Js::OpCode::InitClass:
485528
case Js::OpCode::InitProto:
486529
case Js::OpCode::NewScObjectNoCtor:
530+
case Js::OpCode::NewScObjectNoCtorFull:
487531
if (inGlobOpt)
488532
{
489533
// Opcodes that make an object into a prototype may break object-header-inlining and final type opt.

lib/Backend/IRBuilder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,7 +1674,7 @@ IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0)
16741674
}
16751675

16761676
case Js::OpCode::NewScObjectSimple:
1677-
dstValueType = ValueType::GetObject(ObjectType::Object);
1677+
dstValueType = ValueType::GetObject(ObjectType::UninitializedObject);
16781678
// fall-through
16791679
case Js::OpCode::LdFuncExpr:
16801680
m_func->DisableCanDoInlineArgOpt();
@@ -4992,7 +4992,7 @@ IRBuilder::BuildAuxiliary(Js::OpCode newOpcode, uint32 offset)
49924992
// lower take it from there...
49934993
srcOpnd = IR::IntConstOpnd::New(auxInsn->Offset, TyUint32, m_func);
49944994
dstOpnd = this->BuildDstOpnd(dstRegSlot);
4995-
dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Object));
4995+
dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
49964996
instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
49974997

49984998
// Because we're going to be making decisions based off the value, we have to defer

lib/Backend/Inline.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4501,6 +4501,8 @@ Inline::SplitConstructorCallCommon(
45014501
{
45024502
createObjInstr->SetByteCodeOffset(newObjInstr);
45034503
createObjInstr->GetSrc1()->SetIsJITOptimizedReg(true);
4504+
// We're splitting a single byte code, so the interpreter has to resume from the beginning if we bail out.
4505+
createObjInstr->forcePreOpBailOutIfNeeded = true;
45044506
newObjInstr->InsertBefore(createObjInstr);
45054507

45064508
createObjDst->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));

lib/Backend/Lower.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4580,18 +4580,40 @@ Lowerer::LowerNewScObject(IR::Instr *newObjInstr, bool callCtor, bool hasArgs, b
45804580
{
45814581
Assert(!newObjDst->CanStoreTemp());
45824582
// createObjDst = NewScObject...(ctorOpnd)
4583-
newScHelper = !callCtor ?
4584-
(isBaseClassConstructorNewScObject ?
4585-
(hasArgs ? IR::HelperNewScObjectNoCtorFull : IR::HelperNewScObjectNoArgNoCtorFull) :
4586-
(hasArgs ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArgNoCtor)) :
4587-
(hasArgs || usedFixedCtorCache ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArg);
45884583

45894584
LoadScriptContext(newObjInstr);
4590-
m_lowererMD.LoadHelperArgument(newObjInstr, newObjInstr->GetSrc1());
45914585

4592-
newScObjCall = IR::Instr::New(Js::OpCode::Call, createObjDst, IR::HelperCallOpnd::New(newScHelper, func), func);
4593-
newObjInstr->InsertBefore(newScObjCall);
4594-
m_lowererMD.LowerCall(newScObjCall, 0);
4586+
if (callCtor)
4587+
{
4588+
newScHelper = (hasArgs || usedFixedCtorCache ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArg);
4589+
4590+
m_lowererMD.LoadHelperArgument(newObjInstr, newObjInstr->GetSrc1());
4591+
4592+
newScObjCall = IR::Instr::New(Js::OpCode::Call, createObjDst, IR::HelperCallOpnd::New(newScHelper, func), func);
4593+
newObjInstr->InsertBefore(newScObjCall);
4594+
m_lowererMD.LowerCall(newScObjCall, 0);
4595+
}
4596+
else
4597+
{
4598+
newScHelper =
4599+
(isBaseClassConstructorNewScObject ?
4600+
(hasArgs ? IR::HelperNewScObjectNoCtorFull : IR::HelperNewScObjectNoArgNoCtorFull) :
4601+
(hasArgs ? IR::HelperNewScObjectNoCtor : IR::HelperNewScObjectNoArgNoCtor));
4602+
4603+
// Branch around the helper call to execute the inlined ctor.
4604+
Assert(callCtorLabel != nullptr);
4605+
newObjInstr->InsertAfter(callCtorLabel);
4606+
4607+
// Change the NewScObject* to a helper call on the spot. This generates implicit call bailout for us if we need one.
4608+
m_lowererMD.LoadHelperArgument(newObjInstr, newObjInstr->UnlinkSrc1());
4609+
m_lowererMD.ChangeToHelperCall(newObjInstr, newScHelper);
4610+
4611+
// Then we're done.
4612+
Assert(createObjDst == newObjDst);
4613+
4614+
// Return the first instruction above the region we've just lowered.
4615+
return RemoveLoweredRegionStartMarker(startMarkerInstr);
4616+
}
45954617
}
45964618
}
45974619

@@ -4836,21 +4858,18 @@ bool Lowerer::TryLowerNewScObjectWithFixedCtorCache(IR::Instr* newObjInstr, IR::
48364858
skipNewScObj = false;
48374859
returnNewScObj = false;
48384860

4839-
AssertMsg(!PHASE_OFF(Js::ObjTypeSpecNewObjPhase, this->m_func) || !newObjInstr->HasBailOutInfo(),
4840-
"Why do we have bailout on NewScObject when ObjTypeSpecNewObj is off?");
4841-
48424861
if (PHASE_OFF(Js::FixedNewObjPhase, newObjInstr->m_func) && PHASE_OFF(Js::ObjTypeSpecNewObjPhase, this->m_func))
48434862
{
48444863
return false;
48454864
}
48464865

48474866
JITTimeConstructorCache * ctorCache;
48484867

4849-
if (newObjInstr->HasBailOutInfo() && !newObjInstr->HasLazyBailOut())
4868+
if (newObjInstr->HasBailOutInfo() && !newObjInstr->HasLazyBailOut() && newObjInstr->GetBailOutKindNoBits() == IR::BailOutFailedCtorGuardCheck)
48504869
{
48514870
Assert(newObjInstr->IsNewScObjectInstr());
48524871
Assert(newObjInstr->IsProfiledInstr());
4853-
Assert(newObjInstr->GetBailOutKind() == IR::BailOutFailedCtorGuardCheck || newObjInstr->HasLazyBailOut());
4872+
Assert(newObjInstr->GetBailOutKindNoBits() == IR::BailOutFailedCtorGuardCheck || newObjInstr->HasLazyBailOut());
48544873

48554874
emitBailOut = true;
48564875

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3636,6 +3636,7 @@ void ByteCodeGenerator::StartEmitFunction(ParseNodeFnc *pnodeFnc)
36363636
#if ENABLE_TTD
36373637
&& !funcInfo->GetParsedFunctionBody()->GetScriptContext()->GetThreadContext()->IsRuntimeInTTDMode()
36383638
#endif
3639+
&& !funcInfo->byteCodeFunction->IsCoroutine()
36393640
);
36403641

36413642
if (funcInfo->GetHasCachedScope())
@@ -4051,6 +4052,11 @@ void ByteCodeGenerator::StartEmitCatch(ParseNodeCatch *pnodeCatch)
40514052
sym->SetIsGlobalCatch(true);
40524053
}
40534054

4055+
if (sym->NeedsScopeObject())
4056+
{
4057+
scope->SetIsObject();
4058+
}
4059+
40544060
Assert(sym->GetScopeSlot() == Js::Constants::NoProperty);
40554061
if (sym->NeedsSlotAlloc(this, funcInfo))
40564062
{
@@ -4071,6 +4077,11 @@ void ByteCodeGenerator::StartEmitCatch(ParseNodeCatch *pnodeCatch)
40714077
sym->SetIsGlobalCatch(true);
40724078
}
40734079

4080+
if (sym->NeedsScopeObject())
4081+
{
4082+
scope->SetIsObject();
4083+
}
4084+
40744085
if (scope->GetMustInstantiate())
40754086
{
40764087
if (sym->IsInSlot(this, funcInfo))

0 commit comments

Comments
 (0)