Skip to content

Commit 298641d

Browse files
committed
[MERGE #4682 @MikeHolman] Fix bad interaction with Spectre mitigation and VirtualArray OOB resume
Merge pull request #4682 from MikeHolman:virtualspectre In case of VirtualArrays, we may have eliminated bound check and rely on our AV handling (as long as index is guaranteed to be within 4GB). However, with spectre mitigations we force OOB reads to nullptr. Our exception filter only handles AVs trying to read from the reserved region, so we end up crashing with nullptr deref instead of resuming. This change makes it so that we will only poison in case the index exceeds our 4GB reservation. OS: 15897366
2 parents b7fdba0 + bafcd1f commit 298641d

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

lib/Backend/Lower.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16171,7 +16171,11 @@ Lowerer::GenerateFastElemIIntIndexCommon(
1617116171
if (shouldPoisonLoad)
1617216172
{
1617316173
// Use a mask to prevent arbitrary speculative reads
16174-
if (!headSegmentLengthOpnd)
16174+
if (!headSegmentLengthOpnd
16175+
#if ENABLE_FAST_ARRAYBUFFER
16176+
&& !baseValueType.IsLikelyOptimizedVirtualTypedArray()
16177+
#endif
16178+
)
1617516179
{
1617616180
if (baseValueType.IsLikelyTypedArray())
1617716181
{
@@ -16189,30 +16193,42 @@ Lowerer::GenerateFastElemIIntIndexCommon(
1618916193
}
1619016194
IR::RegOpnd* localMaskOpnd = nullptr;
1619116195
#if TARGET_64
16192-
IR::RegOpnd* headSegmentLengthRegOpnd = IR::RegOpnd::New(headSegmentLengthOpnd->GetType(), m_func);
16193-
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV_TRUNC, headSegmentLengthRegOpnd, headSegmentLengthOpnd, m_func);
16194-
instr->InsertBefore(instrMov);
16195-
LowererMD::Legalize(instrMov);
16196-
16197-
if (headSegmentLengthRegOpnd->GetSize() != MachPtr)
16196+
IR::Opnd* lengthOpnd = nullptr;
16197+
#if ENABLE_FAST_ARRAYBUFFER
16198+
if (baseValueType.IsLikelyOptimizedVirtualTypedArray())
1619816199
{
16199-
headSegmentLengthRegOpnd = headSegmentLengthRegOpnd->UseWithNewType(TyMachPtr, this->m_func)->AsRegOpnd();
16200-
}
16200+
lengthOpnd = IR::IntConstOpnd::New(MAX_ASMJS_ARRAYBUFFER_LENGTH >> indirScale, TyMachReg, m_func);
16201+
}
16202+
else
16203+
#endif
16204+
{
16205+
AnalysisAssert(headSegmentLengthOpnd != nullptr);
16206+
lengthOpnd = IR::RegOpnd::New(headSegmentLengthOpnd->GetType(), m_func);
16207+
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV_TRUNC, lengthOpnd, headSegmentLengthOpnd, m_func);
16208+
instr->InsertBefore(instrMov);
16209+
LowererMD::Legalize(instrMov);
1620116210

16202-
// MOV r1, [opnd + offset(type)]
16211+
if (lengthOpnd->GetSize() != MachPtr)
16212+
{
16213+
lengthOpnd = lengthOpnd->UseWithNewType(TyMachPtr, this->m_func)->AsRegOpnd();
16214+
}
16215+
}
16216+
16217+
16218+
// MOV r1, [opnd + offset(type)]
1620316219
IR::RegOpnd* indexValueRegOpnd = IR::RegOpnd::New(indexValueOpnd->GetType(), m_func);
1620416220

16205-
instrMov = IR::Instr::New(Js::OpCode::MOV_TRUNC, indexValueRegOpnd, indexValueOpnd, m_func);
16221+
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV_TRUNC, indexValueRegOpnd, indexValueOpnd, m_func);
1620616222
instr->InsertBefore(instrMov);
1620716223
LowererMD::Legalize(instrMov);
1620816224

1620916225
if (indexValueRegOpnd->GetSize() != MachPtr)
1621016226
{
1621116227
indexValueRegOpnd = indexValueRegOpnd->UseWithNewType(TyMachPtr, this->m_func)->AsRegOpnd();
16212-
}
16228+
}
1621316229

1621416230
localMaskOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
16215-
InsertSub(false, localMaskOpnd, indexValueRegOpnd, headSegmentLengthRegOpnd, instr);
16231+
InsertSub(false, localMaskOpnd, indexValueRegOpnd, lengthOpnd, instr);
1621616232
InsertShift(Js::OpCode::Shr_A, false, localMaskOpnd, localMaskOpnd, IR::IntConstOpnd::New(63, TyInt8, m_func), instr);
1621716233
#else
1621816234
localMaskOpnd = IR::RegOpnd::New(TyInt32, m_func);

0 commit comments

Comments
 (0)