Skip to content
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
35 changes: 29 additions & 6 deletions src/coreclr/jit/morphblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,10 @@ void MorphInitBlockHelper::PrepareDst()
if (m_dst->IsLocal())
{
m_dstLclNode = m_dst->AsLclVarCommon();
m_dstVarDsc = m_comp->lvaGetDesc(m_dstLclNode);
m_dstLclOffset = m_dstLclNode->GetLclOffs();

if (m_dst->TypeIs(TYP_STRUCT))
{
assert(m_dstVarDsc->GetLayout()->GetSize() == m_dstVarDsc->lvExactSize);
m_blockLayout = m_dstLclNode->GetLayout(m_comp);
}
}
Expand All @@ -212,9 +210,19 @@ void MorphInitBlockHelper::PrepareDst()
ssize_t dstLclOffset = 0;
if (dstAddr->DefinesLocalAddr(&m_dstLclNode, &dstLclOffset))
{
// Note that lclNode can be a field, like `BLK<4> struct(ADD(ADDR(LCL_FLD int), CNST_INT))`.
m_dstVarDsc = m_comp->lvaGetDesc(m_dstLclNode);
m_dstLclOffset = static_cast<unsigned>(dstLclOffset);
// Treat out-of-bounds access to locals opaquely to simplify downstream logic.
unsigned dstLclSize = m_comp->lvaLclExactSize(m_dstLclNode->GetLclNum());

if (!FitsIn<unsigned>(dstLclOffset) ||
((static_cast<uint64_t>(dstLclOffset) + m_dst->AsIndir()->Size()) > dstLclSize))
{
assert(m_comp->lvaGetDesc(m_dstLclNode)->IsAddressExposed());
m_dstLclNode = nullptr;
}
else
{
m_dstLclOffset = static_cast<unsigned>(dstLclOffset);
}
}

if (m_dst->TypeIs(TYP_STRUCT))
Expand All @@ -236,6 +244,10 @@ void MorphInitBlockHelper::PrepareDst()
if (m_dstLclNode != nullptr)
{
m_dstLclNum = m_dstLclNode->GetLclNum();
m_dstVarDsc = m_comp->lvaGetDesc(m_dstLclNum);

assert((m_dstVarDsc->TypeGet() != TYP_STRUCT) ||
(m_dstVarDsc->GetLayout()->GetSize() == m_dstVarDsc->lvExactSize));

// Kill everything about m_dstLclNum (and its field locals)
if (m_comp->optLocalAssertionProp && (m_comp->optAssertionCount > 0))
Expand Down Expand Up @@ -566,7 +578,18 @@ void MorphCopyBlockHelper::PrepareSrc()
ssize_t srcLclOffset = 0;
if (m_src->AsIndir()->Addr()->DefinesLocalAddr(&m_srcLclNode, &srcLclOffset))
{
m_srcLclOffset = static_cast<unsigned>(srcLclOffset);
// Treat out-of-bounds access to locals opaquely to simplify downstream logic.
unsigned srcLclSize = m_comp->lvaLclExactSize(m_srcLclNode->GetLclNum());

if (!FitsIn<unsigned>(srcLclOffset) || ((static_cast<uint64_t>(srcLclOffset) + m_blockSize) > srcLclSize))
{
assert(m_comp->lvaGetDesc(m_srcLclNode)->IsAddressExposed());
m_srcLclNode = nullptr;
}
else
{
m_srcLclOffset = static_cast<unsigned>(srcLclOffset);
}
}
}

Expand Down
82 changes: 82 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_71601/Runtime_71601.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Numerics;
using System.Runtime.CompilerServices;

public class Runtime_71601
{
public static int Main()
{
if (ProblemWithPrimitiveSrc())
{
return 101;
}

if (ProblemWithPrimitiveDst())
{
return 102;
}

return 100;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool ProblemWithPrimitiveSrc()
{
WrapTuple p = new WrapTuple { FieldOne = { Value = 1 }, FieldTwo = { Value = 2 } };
Wrap a = p.FieldTwo;
Wrap b = WrapTuple.GetFieldTwo(ref p);

if (a.Value != b.Value)
{
return true;
}

a = p.FieldOne;
b = WrapTuple.GetFieldOne(ref p);

if (a.Value != b.Value)
{
return true;
}

return false;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool ProblemWithPrimitiveDst()
{
WrapTuple p = new WrapTuple { FieldOne = { Value = 1 }, FieldTwo = { Value = 2 } };
Wrap a = p.FieldTwo;
WrapTuple.GetFieldTwo(ref p) = a;

if (a.Value == p.FieldOne.Value)
{
return true;
}

WrapTuple.GetFieldOne(ref p) = a;

if (a.Value != p.FieldOne.Value)
{
return true;
}

return false;
}

struct WrapTuple
{
public Wrap FieldOne;
public Wrap FieldTwo;

public static ref Wrap GetFieldOne(ref WrapTuple t) => ref Unsafe.Add(ref t.FieldTwo, -1);
public static ref Wrap GetFieldTwo(ref WrapTuple t) => ref Unsafe.Add(ref t.FieldOne, 1);
}

struct Wrap
{
public int Value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>