Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 77e01f5

Browse files
committed
Do not propagate bad assertions from unreachable blocks
Also ensure only valid assertions are utilized.
1 parent 6fd8cd3 commit 77e01f5

File tree

3 files changed

+100
-42
lines changed

3 files changed

+100
-42
lines changed

src/jit/assertionprop.cpp

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -754,12 +754,13 @@ Compiler::AssertionDsc * Compiler::optGetAssertion(AssertionIndex assertIndex)
754754
{
755755
assert(NO_ASSERTION_INDEX == 0);
756756
noway_assert(assertIndex != NO_ASSERTION_INDEX);
757+
noway_assert(assertIndex <= optAssertionCount);
758+
AssertionDsc* assertion = &optAssertionTabPrivate[assertIndex - 1];
759+
#ifdef DEBUG
760+
optDebugCheckAssertion(assertion);
761+
#endif
757762

758-
if (assertIndex > optMaxAssertionCount)
759-
{
760-
return nullptr;
761-
}
762-
return &optAssertionTabPrivate[assertIndex - 1];
763+
return assertion;
763764
}
764765

765766
/*****************************************************************************
@@ -1488,6 +1489,63 @@ Compiler::AssertionIndex Compiler::optAddAssertion(AssertionDsc* newAssertion)
14881489
}
14891490

14901491
#ifdef DEBUG
1492+
void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
1493+
{
1494+
assert(assertion->assertionKind < OAK_COUNT);
1495+
assert(assertion->op1.kind < O1K_COUNT);
1496+
assert(assertion->op2.kind < O2K_COUNT);
1497+
// It would be good to check that op1.vn and op2.vn are valid value numbers.
1498+
1499+
switch(assertion->op1.kind)
1500+
{
1501+
case O1K_LCLVAR:
1502+
case O1K_EXACT_TYPE:
1503+
case O1K_SUBTYPE:
1504+
assert(assertion->op1.lcl.lclNum < lvaCount);
1505+
assert(optLocalAssertionProp ||
1506+
((assertion->op1.lcl.ssaNum - SsaConfig::UNINIT_SSA_NUM) < lvaTable[assertion->op1.lcl.lclNum].lvNumSsaNames));
1507+
break;
1508+
case O1K_ARR_BND:
1509+
// It would be good to check that bnd.vnIdx and bnd.vnLen are valid value numbers.
1510+
break;
1511+
case O1K_ARRLEN_OPER_BND:
1512+
case O1K_ARRLEN_LOOP_BND:
1513+
case O1K_CONSTANT_LOOP_BND:
1514+
assert(!optLocalAssertionProp);
1515+
break;
1516+
default:
1517+
break;
1518+
}
1519+
switch (assertion->op2.kind)
1520+
{
1521+
case O2K_IND_CNS_INT:
1522+
case O2K_CONST_INT:
1523+
{
1524+
// The only flags that can be set are those in the GTF_ICON_HDL_MASK, or bit 0, which is
1525+
// used to indicate a long constant.
1526+
assert((assertion->op2.u1.iconFlags & ~(GTF_ICON_HDL_MASK|1)) == 0);
1527+
switch (assertion->op1.kind)
1528+
{
1529+
case O1K_EXACT_TYPE:
1530+
case O1K_SUBTYPE:
1531+
assert(assertion->op2.u1.iconFlags != 0);
1532+
break;
1533+
case O1K_LCLVAR:
1534+
case O1K_ARR_BND:
1535+
assert(lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF || assertion->op2.u1.iconVal == 0);
1536+
break;
1537+
default:
1538+
break;
1539+
}
1540+
}
1541+
break;
1542+
1543+
default:
1544+
// for all other 'assertion->op2.kind' values we don't check anything
1545+
break;
1546+
}
1547+
}
1548+
14911549
/*****************************************************************************
14921550
*
14931551
* Verify that assertion prop related assumptions are valid. If "index"
@@ -1502,33 +1560,7 @@ void Compiler::optDebugCheckAssertions(AssertionIndex index)
15021560
for (AssertionIndex ind = start; ind <= end; ++ind)
15031561
{
15041562
AssertionDsc* assertion = optGetAssertion(ind);
1505-
switch (assertion->op2.kind)
1506-
{
1507-
case O2K_IND_CNS_INT:
1508-
case O2K_CONST_INT:
1509-
{
1510-
switch (assertion->op1.kind)
1511-
{
1512-
case O1K_EXACT_TYPE:
1513-
case O1K_SUBTYPE:
1514-
assert(assertion->op2.u1.iconFlags != 0);
1515-
break;
1516-
case O1K_ARRLEN_OPER_BND:
1517-
case O1K_ARRLEN_LOOP_BND:
1518-
case O1K_CONSTANT_LOOP_BND:
1519-
assert(!optLocalAssertionProp);
1520-
break;
1521-
default:
1522-
assert(lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF || assertion->op2.u1.iconVal == 0);
1523-
break;
1524-
}
1525-
}
1526-
break;
1527-
1528-
default:
1529-
// for all other 'assertion->op2.kind' values we don't check anything
1530-
break;
1531-
}
1563+
optDebugCheckAssertion(assertion);
15321564
}
15331565
}
15341566
#endif
@@ -4282,6 +4314,18 @@ ASSERT_TP* Compiler::optInitAssertionDataflowFlags()
42824314
{
42834315
ASSERT_TP* jumpDestOut = fgAllocateTypeForEachBlk<ASSERT_TP>();
42844316

4317+
// The local assertion gen phase may have created unreachable blocks.
4318+
// They will never be visited in the dataflow propagation phase, so they need to
4319+
// be initialized correctly. This means that instead of setting their sets to
4320+
// apFull (i.e. all possible bits set), we need to set the bits only for valid
4321+
// assertions (note that at this point we are not creating any new assertions).
4322+
// Also note that assertion indices start from 1.
4323+
ASSERT_TP apValidFull = optNewEmptyAssertSet();
4324+
for (int i = 1; i <= optAssertionCount; i++)
4325+
{
4326+
BitVecOps::AddElemD(apTraits, apValidFull, i-1);
4327+
}
4328+
42854329
// Initially estimate the OUT sets to everything except killed expressions
42864330
// Also set the IN sets to 1, so that we can perform the intersection.
42874331
// Also, zero-out the flags for handler blocks, as we could be in the
@@ -4290,11 +4334,16 @@ ASSERT_TP* Compiler::optInitAssertionDataflowFlags()
42904334
// edges.
42914335
for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
42924336
{
4293-
block->bbAssertionIn = bbIsHandlerBeg(block) ? optNewEmptyAssertSet() : optNewFullAssertSet();
4337+
block->bbAssertionIn = optNewEmptyAssertSet();
4338+
if (!bbIsHandlerBeg(block))
4339+
{
4340+
BitVecOps::Assign(apTraits, block->bbAssertionIn, apValidFull);
4341+
}
42944342
block->bbAssertionGen = optNewEmptyAssertSet();
4295-
block->bbAssertionOut = optNewFullAssertSet();
4343+
block->bbAssertionOut = optNewEmptyAssertSet();
4344+
BitVecOps::Assign(apTraits, block->bbAssertionOut, apValidFull);
42964345
jumpDestOut[block->bbNum] = optNewEmptyAssertSet();
4297-
BitVecOps::Assign(apTraits, jumpDestOut[block->bbNum], apFull);
4346+
BitVecOps::Assign(apTraits, jumpDestOut[block->bbNum], apValidFull);
42984347
}
42994348
// Compute the data flow values for all tracked expressions
43004349
// IN and OUT never change for the initial basic block B1
@@ -4817,9 +4866,9 @@ void Compiler::optAssertionPropMain()
48174866
// and thus we must morph, set order, re-link
48184867
for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
48194868
{
4820-
JITDUMP("Propagating %s assertions for BB%02d, stmt %08X, tree %08X, tree -> %d\n",
4821-
BitVecOps::ToString(apTraits, assertions),
4822-
block->bbNum, dspPtr(stmt), dspPtr(tree), tree->GetAssertion());
4869+
JITDUMP("Propagating %s assertions for BB%02d, stmt [%06d], tree [%06d], tree -> %d\n",
4870+
BitVecOps::ToString(apTraits, assertions),
4871+
block->bbNum, dspTreeID(stmt), dspTreeID(tree), tree->GetAssertion());
48234872

48244873
GenTreePtr newTree = optAssertionProp(assertions, tree, stmt);
48254874
if (newTree)

src/jit/compiler.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5589,7 +5589,8 @@ protected :
55895589
OAK_EQUAL,
55905590
OAK_NOT_EQUAL,
55915591
OAK_SUBRANGE,
5592-
OAK_NO_THROW };
5592+
OAK_NO_THROW,
5593+
OAK_COUNT };
55935594

55945595
enum optOp1Kind { O1K_INVALID,
55955596
O1K_LCLVAR,
@@ -5598,7 +5599,8 @@ protected :
55985599
O1K_ARRLEN_LOOP_BND,
55995600
O1K_CONSTANT_LOOP_BND,
56005601
O1K_EXACT_TYPE,
5601-
O1K_SUBTYPE };
5602+
O1K_SUBTYPE,
5603+
O1K_COUNT };
56025604

56035605
enum optOp2Kind { O2K_INVALID,
56045606
O2K_LCLVAR_COPY,
@@ -5607,7 +5609,8 @@ protected :
56075609
O2K_CONST_LONG,
56085610
O2K_CONST_DOUBLE,
56095611
O2K_ARR_LEN,
5610-
O2K_SUBRANGE };
5612+
O2K_SUBRANGE,
5613+
O2K_COUNT };
56115614
struct AssertionDsc
56125615
{
56135616
optAssertionKind assertionKind;
@@ -5783,6 +5786,10 @@ protected :
57835786
case O2K_INVALID:
57845787
// we will return false
57855788
break;
5789+
5790+
default:
5791+
assert(!"Unexpected value for op2.kind in AssertionDsc.");
5792+
break;
57865793
}
57875794
return false;
57885795
}
@@ -5921,6 +5928,7 @@ public :
59215928

59225929
#ifdef DEBUG
59235930
void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex=0);
5931+
void optDebugCheckAssertion(AssertionDsc* assertion);
59245932
void optDebugCheckAssertions(AssertionIndex AssertionIndex);
59255933
#endif
59265934
void optAddCopies();

src/jit/compiler.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3476,8 +3476,9 @@ void Compiler::optAssertionReset(AssertionIndex limit)
34763476

34773477
while (optAssertionCount > limit)
34783478
{
3479-
AssertionIndex index = optAssertionCount--;
3479+
AssertionIndex index = optAssertionCount;
34803480
AssertionDsc* curAssertion = optGetAssertion(index);
3481+
optAssertionCount--;
34813482
unsigned lclNum = curAssertion->op1.lcl.lclNum;
34823483
assert(lclNum < lvaTableCnt);
34833484
BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);

0 commit comments

Comments
 (0)