Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

17-12 Security Update #4411

Merged
merged 16 commits into from
Dec 12, 2017
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Build/NuGet/.pack-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.7.4
1.7.5
8 changes: 8 additions & 0 deletions lib/Backend/BackwardPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7853,6 +7853,14 @@ BackwardPass::RemoveEmptyLoopAfterMemOp(Loop *loop)

outerBlock->RemovePred(head, this->func->m_fg);
landingPad->RemoveSucc(head, this->func->m_fg);
Assert(landingPad->GetSuccList()->Count() == 0);

IR::Instr* firstOuterInstr = outerBlock->GetFirstInstr();
AssertOrFailFast(firstOuterInstr->IsLabelInstr() && !landingPad->GetLastInstr()->EndsBasicBlock());
IR::LabelInstr* label = firstOuterInstr->AsLabelInstr();
// Add br to Outer block to keep coherence between branches and flow graph
IR::BranchInstr *outerBr = IR::BranchInstr::New(Js::OpCode::Br, label, this->func);
landingPad->InsertAfter(outerBr);
this->func->m_fg->AddEdge(landingPad, outerBlock);

this->func->m_fg->RemoveBlock(head, nullptr);
Expand Down
10 changes: 6 additions & 4 deletions lib/Backend/GlobOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12946,7 +12946,9 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr)
Assert(kills.KillsTypedArrayHeadSegmentLengths());

// - Calls need to kill the value types of values in the following list. For instance, calls can transform a JS array
// into an ES5 array, so any definitely-array value types need to be killed. Update the value types.
// into an ES5 array, so any definitely-array value types need to be killed. Also, VirtualTypeArrays do not have
// bounds checks; this can be problematic if the array is detached, so check to ensure that it is a virtual array.
// Update the value types to likley to ensure a bailout that asserts Array type is generated.
// - Calls also need to kill typed array head segment lengths. A typed array's array buffer may be transferred to a web
// worker, in which case the typed array's length is set to zero.
for(auto it = valuesToKillOnCalls->GetIterator(); it.IsValid(); it.MoveNext())
Expand All @@ -12956,7 +12958,7 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr)
Assert(
valueInfo->IsArrayOrObjectWithArray() ||
valueInfo->IsOptimizedTypedArray() && valueInfo->AsArrayValueInfo()->HeadSegmentLengthSym());
if(valueInfo->IsArrayOrObjectWithArray())
if (valueInfo->IsArrayOrObjectWithArray() || valueInfo->IsOptimizedVirtualTypedArray())
{
ChangeValueType(nullptr, value, valueInfo->Type().ToLikely(), false);
continue;
Expand Down Expand Up @@ -18165,8 +18167,8 @@ GlobOpt::TrackTempObjectSyms(IR::Instr * instr, IR::RegOpnd * opnd)
(instr->GetSrc1()->IsRegOpnd() && globOptData.canStoreTempObjectSyms->Test(instr->GetSrc1()->AsRegOpnd()->m_sym->m_id))
&& (!instr->GetSrc2() || (instr->GetSrc2()->IsRegOpnd() && globOptData.canStoreTempObjectSyms->Test(instr->GetSrc2()->AsRegOpnd()->m_sym->m_id))));

Assert(!canStoreTemp || instr->dstIsTempObject);
Assert(!maybeTemp || instr->dstIsTempObject);
AssertOrFailFast(!canStoreTemp || instr->dstIsTempObject);
AssertOrFailFast(!maybeTemp || instr->dstIsTempObject);
}

// Need to get the var equiv sym as assignment of type specialized sym kill the var sym value anyway.
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/IRBuilderAsmJs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@ IRBuilderAsmJs::CreateLabel(IR::BranchInstr * branchInstr, uint & offset)
}

IR::LabelInstr * labelInstr;
if (instrPrev && instrPrev->IsLabelInstr() && instrPrev->GetByteCodeOffset() == offset)
if (instrPrev && instrPrev->IsLabelInstr())
{
// Found an existing label at the right offset. Just reuse it.
labelInstr = instrPrev->AsLabelInstr();
Expand Down
91 changes: 56 additions & 35 deletions lib/Backend/Inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1983,19 +1983,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
StackSym* originalCallTargetStackSym = callInstr->GetSrc1()->GetStackSym();
bool originalCallTargetOpndIsJITOpt = callInstr->GetSrc1()->GetIsJITOptimizedReg();

// We are committed to inlining, optimize the call instruction for fixed fields now and don't attempt it later.
bool safeThis = false;
if (TryOptimizeCallInstrWithFixedMethod(callInstr, inlineeData, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/, safeThis /*unused here*/))
{
Assert(callInstr->m_opcode == Js::OpCode::CallIFixed);
Assert(callInstr->GetFixedFunction()->GetFuncInfoAddr() == inlineeData->GetFunctionInfoAddr());
}
else
{
// FunctionObject check for built-ins
IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func);
InsertFunctionObjectCheck(callInstr, callInstr, bailOutInstr, inlineeData);
}
IR::ByteCodeUsesInstr* useCallTargetInstr = EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, inlineeData, false, true, false, true);

// To push function object for cases when we have to make calls to helper method to assist in inlining
if(inlineCallOpCode == Js::OpCode::CallDirect)
Expand Down Expand Up @@ -2031,11 +2019,9 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *
}
}

// Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point
// at which we may need to call the inlinee again in the interpreter.
if (useCallTargetInstr)
{
IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr);
useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id);
useCallTargetInstr->Unlink();
callInstr->InsertBefore(useCallTargetInstr);
}

Expand Down Expand Up @@ -2071,7 +2057,7 @@ Inline::InlineBuiltInFunction(IR::Instr *callInstr, const FunctionJITTimeInfo *

// Insert a byteCodeUsesInstr to make sure the function object's lifetime is extended beyond the last bailout point
// at which we may need to call the inlinee again in the interpreter.
IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr->GetPrevRealInstrOrLabel());
useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr->GetPrevRealInstrOrLabel());
useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetOpndIsJITOpt, originalCallTargetStackSym->m_id);

if(inlineCallOpCode == Js::OpCode::InlineArrayPop)
Expand Down Expand Up @@ -2364,7 +2350,7 @@ IR::Instr* Inline::InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo *

// TODO: OOP JIT enable assert (readprocessmemory?)
//Assert((inlineeData->GetFunctionInfo()->GetAttributes() & Js::FunctionInfo::Attributes::BuiltInInlinableAsLdFldInlinee) != 0);
return InlineApplyWithArray(callInstr, applyData, Js::JavascriptLibrary::GetBuiltInForFuncInfo(inlineeData->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo()));
return InlineApplyBuiltInTargetWithArray(callInstr, applyData, inlineeData);
}
else
{
Expand Down Expand Up @@ -2477,15 +2463,33 @@ IR::Instr * Inline::InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::In
/*
This method will only do CallDirect style inlining of built-in targets. No script function inlining.
*/
IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJITTimeInfo * funcInfo, Js::BuiltinFunction builtInId)
IR::Instr * Inline::InlineApplyBuiltInTargetWithArray(IR::Instr * callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * builtInInfo)
{
IR::Instr * implicitThisArgOut = nullptr;
IR::Instr * explicitThisArgOut = nullptr;
IR::Instr * arrayArgOut = nullptr;
uint argOutCount = 0;
this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &arrayArgOut, argOutCount);

TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
Js::OpCode originalCallOpcode = callInstr->m_opcode;
IR::Opnd * originalCallSrc1 = callInstr->GetSrc1()->Copy(this->topFunc);
IR::AutoReuseOpnd autoReuseOriginalCallSrc1(originalCallSrc1, this->topFunc);

IR::Instr* applyLdInstr = nullptr;
IR::Instr* applyTargetLdInstr = nullptr;
if (!TryGetApplyAndTargetLdInstrs(callInstr, &applyLdInstr, &applyTargetLdInstr))
{
return callInstr;
}

// Fixed function/function object checks for target built-in
callInstr->ReplaceSrc1(applyTargetLdInstr->GetDst());
EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, builtInInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);

// Fixed function/function object checks for .apply
callInstr->m_opcode = originalCallOpcode;
callInstr->ReplaceSrc1(originalCallSrc1);
EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);

IR::Instr* builtInEndInstr = InsertInlineeBuiltInStartEndTags(callInstr, 3); // 3 args (implicit this + explicit this + array = 3)
builtInEndInstr->m_opcode = Js::OpCode::InlineNonTrackingBuiltInEnd; // We will call EndTrackCall when we see CallDirect for reasons explained in GlobOpt::TrackCalls
Expand Down Expand Up @@ -2513,6 +2517,7 @@ IR::Instr * Inline::InlineApplyWithArray(IR::Instr * callInstr, const FunctionJI
argOut = IR::Instr::New(Js::OpCode::ArgOut_A_InlineSpecialized, linkOpnd, implicitThisArgOut->GetSrc1(), argOut->GetDst(), callInstr->m_func);
callInstr->InsertBefore(argOut);

Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInForFuncInfo(builtInInfo->GetFunctionInfoAddr(), this->topFunc->GetThreadContextInfo());
IR::HelperCallOpnd * helperCallOpnd = nullptr;
switch (builtInId)
{
Expand Down Expand Up @@ -2543,7 +2548,7 @@ IR::Instr * Inline::InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const
uint argOutCount = 0;
this->GetArgInstrsForCallAndApply(callInstr, &implicitThisArgOut, &explicitThisArgOut, &dummyInstr, argOutCount);

TryFixedMethodAndPrepareInsertionPoint(callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, applyInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);

InsertInlineeBuiltInStartEndTags(callInstr, 2); // 2 args (implicit this + explicit this)

Expand Down Expand Up @@ -2616,6 +2621,22 @@ void Inline::GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** impli
linkOpnd->AsRegOpnd()->m_sym->m_isInlinedArgSlot = true;
}

bool Inline::TryGetApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_result_maybenull_ IR::Instr ** applyLdInstr, _Outptr_result_maybenull_ IR::Instr ** applyTargetLdInstr)
{
IR::Opnd* applyOpnd = callInstr->GetSrc1();
Assert(applyOpnd->IsRegOpnd());
StackSym* applySym = applyOpnd->AsRegOpnd()->m_sym->AsStackSym();
if (!applySym->IsSingleDef())
{
*applyLdInstr = nullptr;
*applyTargetLdInstr = nullptr;
return false;
}
*applyLdInstr = applySym->GetInstrDef();;
*applyTargetLdInstr = (*applyLdInstr)->m_prev;
return true;
}

/*
This method only inlines targets which are script functions, under the
condition that the second argument (if any) passed to apply is arguments object.
Expand All @@ -2637,16 +2658,13 @@ bool Inline::InlineApplyScriptTarget(IR::Instr *callInstr, const FunctionJITTime

// Begin inlining apply target

IR::Opnd* applyOpnd = callInstr->GetSrc1();
Assert(applyOpnd->IsRegOpnd());
StackSym* applySym = applyOpnd->AsRegOpnd()->m_sym->AsStackSym();
if (!applySym->IsSingleDef())
IR::Instr* applyLdInstr = nullptr;
IR::Instr* applyTargetLdInstr = nullptr;
if (!TryGetApplyAndTargetLdInstrs(callInstr, &applyLdInstr, &applyTargetLdInstr))
{
return false;
}
IR::Instr* applyLdInstr = applySym->GetInstrDef();
IR::Instr* applyTargetLdInstr = applyLdInstr->m_prev;


if(applyTargetLdInstr->m_opcode != Js::OpCode::LdFldForCallApplyTarget ||
((applyTargetLdInstr->AsProfiledInstr()->u.FldInfo().flags & Js::FldInfo_FromAccessor) != 0))
{
Expand Down Expand Up @@ -2908,7 +2926,7 @@ Inline::InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, co

IR::SymOpnd* orgLinkOpnd = callInstr->GetSrc2()->AsSymOpnd();

TryFixedMethodAndPrepareInsertionPoint(callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);
EmitFixedMethodOrFunctionObjectChecksForBuiltIns(callInstr, callInstr, funcInfo, false /*isPolymorphic*/, true /*isBuiltIn*/, false /*isCtor*/, true /*isInlined*/);

InsertInlineeBuiltInStartEndTags(callInstr, actualCount);

Expand Down Expand Up @@ -4225,26 +4243,29 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
return primaryBailOutInstr;
}

void
Inline::TryFixedMethodAndPrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
IR::ByteCodeUsesInstr*
Inline::EmitFixedMethodOrFunctionObjectChecksForBuiltIns(IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined)
{
StackSym* originalCallTargetStackSym = callInstr->GetSrc1()->GetStackSym();
bool originalCallTargetIsJITOpt = callInstr->GetSrc1()->GetIsJITOptimizedReg();

IR::ByteCodeUsesInstr * useCallTargetInstr = nullptr;
bool safeThis = false;
if (TryOptimizeCallInstrWithFixedMethod(callInstr, inlineeInfo, isPolymorphic, isBuiltIn, isCtor, isInlined, safeThis))
{
Assert(callInstr->m_opcode == Js::OpCode::CallIFixed);

Assert(callInstr->GetFixedFunction()->GetFuncInfoAddr() == inlineeInfo->GetFunctionInfoAddr());
// If we optimized the call instruction for a fixed function, we must extend the function object's lifetime until after the last bailout before the call.
IR::ByteCodeUsesInstr * useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr);
useCallTargetInstr = IR::ByteCodeUsesInstr::New(callInstr);
useCallTargetInstr->SetRemovedOpndSymbol(originalCallTargetIsJITOpt, originalCallTargetStackSym->m_id);
callInstr->InsertBefore(useCallTargetInstr);
}
else
{
PrepareInsertionPoint(callInstr, inlineeInfo, callInstr);
IR::BailOutInstr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotBuiltIn, IR::BailOutOnInlineFunction, callInstr, callInstr->m_func);
InsertFunctionObjectCheck(callInstr, funcObjCheckInsertInstr, bailOutInstr, inlineeInfo);
}
return useCallTargetInstr;
}

uint Inline::CountActuals(IR::Instr *callInstr)
Expand Down
6 changes: 3 additions & 3 deletions lib/Backend/Inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ class Inline
IR::Instr * SimulateCallForGetterSetter(IR::Instr *accessorInstr, IR::Instr* insertInstr, IR::PropertySymOpnd* methodOpnd, bool isGetter);

IR::Instr * InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo * applyData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth, uint argsCount);
IR::Instr * InlineApplyWithArray(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, Js::BuiltinFunction builtInId);
IR::Instr * InlineApplyBuiltInTargetWithArray(IR::Instr *callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * builtInInfo);
IR::Instr * InlineApplyWithArgumentsObject(IR::Instr * callInstr, IR::Instr * argsObjectArgInstr, const FunctionJITTimeInfo * inlineeInfo);
IR::Instr * InlineApplyWithoutArrayArgument(IR::Instr *callInstr, const FunctionJITTimeInfo * applyInfo, const FunctionJITTimeInfo * applyTargetInfo);
bool InlineApplyScriptTarget(IR::Instr *callInstr, const FunctionJITTimeInfo* inlinerData, const FunctionJITTimeInfo** pInlineeData, const FunctionJITTimeInfo * applyFuncInfo,
const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth, bool isArrayOpndArgumentsObject, uint argsCount);
void GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** implicitThisArgOut, IR::Instr** explicitThisArgOut, IR::Instr** argumentsOrArrayArgOut, uint &argOutCount);

bool TryGetApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_result_maybenull_ IR::Instr ** applyLdInstr, _Outptr_result_maybenull_ IR::Instr ** applyTargetLdInstr);
IR::Instr * InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth);
bool InlineCallTarget(IR::Instr *callInstr, const FunctionJITTimeInfo* inlinerData, const FunctionJITTimeInfo** pInlineeData, const FunctionJITTimeInfo *callFuncInfo,
const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth);
Expand Down Expand Up @@ -83,7 +83,7 @@ class Inline
void FixupExtraActualParams(IR::Instr * instr, IR::Instr *argOuts[], IR::Instr *argOutsExtra[], uint index, uint actualCount, Js::ProfileId callSiteId);
void RemoveExtraFixupArgouts(IR::Instr* instr, uint argoutRemoveCount, Js::ProfileId callSiteId);
IR::Instr* PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind = IR::BailOutOnInlineFunction);
void TryFixedMethodAndPrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined);
IR::ByteCodeUsesInstr* EmitFixedMethodOrFunctionObjectChecksForBuiltIns(IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined);
Js::ArgSlot MapActuals(IR::Instr *callInstr, __out_ecount(maxParamCount) IR::Instr *argOuts[], Js::ArgSlot formalCount, Func *inlinee, Js::ProfileId callSiteId, bool *stackArgsArgOutExpanded, IR::Instr *argOutsExtra[] = nullptr, Js::ArgSlot maxParamCount = Js::InlineeCallInfo::MaxInlineeArgoutCount);
uint32 CountActuals(IR::Instr *callIntr);
void MapFormals(Func *inlinee, __in_ecount(formalCount) IR::Instr *argOuts[], uint formalCount, uint actualCount, IR::RegOpnd *retOpnd, IR::Opnd * funcObjOpnd, const StackSym *symCallerThis, bool stackArgsArgOutExpanded, bool fixedFunctionSafeThis = false, IR::Instr *argOutsExtra[] = nullptr);
Expand Down
Loading