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

JIT: Fix bug in finally cloning caused by unsound callfinally reordering #18348

Merged
merged 2 commits into from
Jun 8, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
49 changes: 32 additions & 17 deletions src/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24492,32 +24492,44 @@ void Compiler::fgCloneFinally()
// We better have found at least one call finally.
assert(firstCallFinallyBlock != nullptr);

// If there is more than one callfinally, move the one we are
// going to retarget to be first in the callfinally range.
// If there is more than one callfinally, we'd like to move
// the one we are going to retarget to be first in the callfinally,
// but only if it's targeted by the last block in the try range.
if (firstCallFinallyBlock != normalCallFinallyBlock)
{
JITDUMP("Moving callfinally BB%02u to be first in line, before BB%02u\n", normalCallFinallyBlock->bbNum,
firstCallFinallyBlock->bbNum);

BasicBlock* const firstToMove = normalCallFinallyBlock;
BasicBlock* const lastToMove = normalCallFinallyBlock->bbNext;
BasicBlock* const placeToMoveAfter = firstCallFinallyBlock->bbPrev;

fgUnlinkRange(firstToMove, lastToMove);
fgMoveBlocksAfter(firstToMove, lastToMove, placeToMoveAfter);
if ((placeToMoveAfter->bbJumpKind == BBJ_ALWAYS) &&
(placeToMoveAfter->bbJumpDest == normalCallFinallyBlock))
{
JITDUMP("Moving callfinally BB%02u to be first in line, before BB%02u\n",
normalCallFinallyBlock->bbNum, firstCallFinallyBlock->bbNum);

BasicBlock* const firstToMove = normalCallFinallyBlock;
BasicBlock* const lastToMove = normalCallFinallyBlock->bbNext;

fgUnlinkRange(firstToMove, lastToMove);
fgMoveBlocksAfter(firstToMove, lastToMove, placeToMoveAfter);

#ifdef DEBUG
// Sanity checks
fgDebugCheckBBlist(false, false);
fgVerifyHandlerTab();
// Sanity checks
fgDebugCheckBBlist(false, false);
fgVerifyHandlerTab();
#endif // DEBUG

assert(nextBlock == lastBlock->bbNext);
assert(nextBlock == lastBlock->bbNext);

// Update where the callfinally range begins, since we might
// have altered this with callfinally rearrangement, and/or
// the range begin might have been pretty loose to begin with.
firstCallFinallyRangeBlock = normalCallFinallyBlock;
// Update where the callfinally range begins, since we might
// have altered this with callfinally rearrangement, and/or
// the range begin might have been pretty loose to begin with.
firstCallFinallyRangeBlock = normalCallFinallyBlock;
}
else
{
JITDUMP("Can't move callfinally BB%02u to be first in line"
" -- last finally block BB%02u doesn't jump to it\n",
normalCallFinallyBlock->bbNum, placeToMoveAfter->bbNum);
}
}
}

Expand Down Expand Up @@ -24690,6 +24702,9 @@ void Compiler::fgCloneFinally()
{
// We can't retarget this call since it
// returns somewhere else.
JITDUMP("Can't retarget callfinally in BB%02u as it jumps to BB%02u, not BB%02u\n",
currentBlock->bbNum, postTryFinallyBlock->bbNum, normalCallFinallyReturn->bbNum);

retargetedAllCalls = false;
}
}
Expand Down
56 changes: 56 additions & 0 deletions tests/src/JIT/Regression/JitBlue/GitHub_18332/GitHub_18332.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;

internal class Foo : IDisposable
{
public void Dispose()
{
}
}

class GitHub_18332
{
// In Aargh there is a finally with two distinct exit paths.
// Finally cloning may choose the non-fall through ("wibble") exit
// path to clone, and then will try to incorrectly arrange for
// that path to become the fall through.
public static string Aargh()
{
using (var foo = new Foo())
{
foreach (var i in new List<int>())
{
try
{
Console.WriteLine("here");
}
catch (Exception)
{
return "wibble";
}
}

foreach (var i in new List<int>())
{
}
}

return "wobble";
}

public static int Main(string[] args)
{
string expected = "wobble";
string actual = Aargh();
if (actual != expected)
{
Console.WriteLine($"FAIL: Aargh() returns '{actual}' expected '{expected}'");
return 0;
}
return 100;
}
}
34 changes: 34 additions & 0 deletions tests/src/JIT/Regression/JitBlue/GitHub_18332/GitHub_18332.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
<OutputType>Exe</OutputType>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
<ItemGroup>
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
<Visible>False</Visible>
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<PropertyGroup>
<DebugType></DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="GitHub_18332.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
</Project>