Skip to content

Commit 4d2ecdc

Browse files
[release/9.0-staging] JIT: Include more edges in BlockDominancePreds to avoid a JIT crash (#110568)
Because of spurious flow it is possible that the preds of the try-begin block are not the only blocks that can dominate a handler. We handled this possibility, but only for finally/fault blocks that can directly have these edges. However, even other handler blocks can be reachable through spurious paths that involves finally/fault blocks, and in these cases returning the preds of the try-begin block is not enough to compute the right dominator statically.
1 parent 7eb5ef2 commit 4d2ecdc

File tree

3 files changed

+86
-35
lines changed

3 files changed

+86
-35
lines changed

src/coreclr/jit/block.cpp

+15-35
Original file line numberDiff line numberDiff line change
@@ -267,15 +267,21 @@ FlowEdge* Compiler::BlockPredsWithEH(BasicBlock* blk)
267267
// 'blk'.
268268
//
269269
// Arguments:
270-
// blk - Block to get dominance predecessors for.
270+
// blk - Block to get dominance predecessors for.
271271
//
272272
// Returns:
273-
// List of edges.
273+
// List of edges.
274274
//
275275
// Remarks:
276-
// Differs from BlockPredsWithEH only in the treatment of handler blocks;
277-
// enclosed blocks are never dominance preds, while all predecessors of
278-
// blocks in the 'try' are (currently only the first try block expected).
276+
// Differs from BlockPredsWithEH only in the treatment of handler blocks;
277+
// enclosed blocks are never dominance preds, while all predecessors of
278+
// blocks in the 'try' are (currently only the first try block expected).
279+
//
280+
// There are additional complications due to spurious flow because of
281+
// two-pass EH. In the flow graph with EH edges we can see entries into the
282+
// try from filters outside the try, to blocks other than the "try-begin"
283+
// block. Hence we need to consider the full set of blocks in the try region
284+
// when considering the block dominance preds.
279285
//
280286
FlowEdge* Compiler::BlockDominancePreds(BasicBlock* blk)
281287
{
@@ -284,44 +290,18 @@ FlowEdge* Compiler::BlockDominancePreds(BasicBlock* blk)
284290
return blk->bbPreds;
285291
}
286292

287-
EHblkDsc* ehblk = ehGetBlockHndDsc(blk);
288-
if (!ehblk->HasFinallyOrFaultHandler() || (ehblk->ebdHndBeg != blk))
289-
{
290-
return ehblk->ebdTryBeg->bbPreds;
291-
}
292-
293-
// Finally/fault handlers can be preceded by enclosing filters due to 2
294-
// pass EH, so add those and keep them cached.
295293
BlockToFlowEdgeMap* domPreds = GetDominancePreds();
296294
FlowEdge* res;
297295
if (domPreds->Lookup(blk, &res))
298296
{
299297
return res;
300298
}
301299

302-
res = ehblk->ebdTryBeg->bbPreds;
303-
if (ehblk->HasFinallyOrFaultHandler() && (ehblk->ebdHndBeg == blk))
300+
EHblkDsc* ehblk = ehGetBlockHndDsc(blk);
301+
res = BlockPredsWithEH(blk);
302+
for (BasicBlock* predBlk : ehblk->ebdTryBeg->PredBlocks())
304303
{
305-
// block is a finally or fault handler; all enclosing filters are predecessors
306-
unsigned enclosing = ehblk->ebdEnclosingTryIndex;
307-
while (enclosing != EHblkDsc::NO_ENCLOSING_INDEX)
308-
{
309-
EHblkDsc* enclosingDsc = ehGetDsc(enclosing);
310-
if (enclosingDsc->HasFilter())
311-
{
312-
for (BasicBlock* filterBlk = enclosingDsc->ebdFilter; filterBlk != enclosingDsc->ebdHndBeg;
313-
filterBlk = filterBlk->Next())
314-
{
315-
res = new (this, CMK_FlowEdge) FlowEdge(filterBlk, blk, res);
316-
317-
assert(filterBlk->VisitEHEnclosedHandlerSecondPassSuccs(this, [blk](BasicBlock* succ) {
318-
return succ == blk ? BasicBlockVisit::Abort : BasicBlockVisit::Continue;
319-
}) == BasicBlockVisit::Abort);
320-
}
321-
}
322-
323-
enclosing = enclosingDsc->ebdEnclosingTryIndex;
324-
}
304+
res = new (this, CMK_FlowEdge) FlowEdge(predBlk, blk, res);
325305
}
326306

327307
domPreds->Set(blk, res);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using Xunit;
7+
8+
public class Runtime_109981
9+
{
10+
[Fact]
11+
public static int TestEntryPoint() => Foo(14);
12+
13+
public static int Foo(int x)
14+
{
15+
if (x == 123)
16+
return 0;
17+
18+
int sum = 9;
19+
for (int i = 0; i < x; i++)
20+
{
21+
sum += i;
22+
}
23+
24+
try
25+
{
26+
if (x != 123)
27+
return sum;
28+
29+
try
30+
{
31+
try
32+
{
33+
Bar();
34+
}
35+
finally
36+
{
37+
sum += 1000;
38+
}
39+
}
40+
catch (ArgumentException)
41+
{
42+
sum += 10000;
43+
}
44+
}
45+
catch when (Filter())
46+
{
47+
sum += 100000;
48+
}
49+
50+
return sum;
51+
}
52+
53+
[MethodImpl(MethodImplOptions.NoInlining)]
54+
private static void Bar()
55+
{
56+
}
57+
58+
[MethodImpl(MethodImplOptions.NoInlining)]
59+
private static bool Filter()
60+
{
61+
return true;
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>True</Optimize>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="$(MSBuildProjectName).cs" />
7+
</ItemGroup>
8+
</Project>

0 commit comments

Comments
 (0)