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
8 changes: 4 additions & 4 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3644,15 +3644,15 @@ void Lowering::LowerRetStruct(GenTreeUnOp* ret)
assert(ret->OperIs(GT_RETURN));
assert(varTypeIsStruct(ret));

GenTree* retVal = ret->gtGetOp1();
GenTree* retVal = ret->gtGetOp1();
var_types nativeReturnType = comp->info.compRetNativeType;
// Note: small types are returned as INT.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that comment still correct with your changes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be still relevant, the following genActualType should upscale all small-types to int

Copy link
Member Author

@jakobbotsch jakobbotsch Apr 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, there are two nodes here, the return and the operand of the return. The return is still wide but the bug was that we were retyping the operand to a wider type, which is wrong.

var_types nativeReturnType = genActualType(comp->info.compRetNativeType);
ret->ChangeType(nativeReturnType);
ret->ChangeType(genActualType(nativeReturnType));

switch (retVal->OperGet())
{
case GT_CALL:
assert(retVal->TypeIs(nativeReturnType)); // Type should be changed during call processing.
assert(retVal->TypeIs(genActualType(nativeReturnType))); // Type should be changed during call processing.
break;

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

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

public unsafe class Runtime_58874
{
private static int Main(string[] args)
{
using EndOfPage endOfPage = EndOfPage.Create();
if (endOfPage != null)
{
Foo(endOfPage.Pointer);
}
return 100;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static Test Foo(Test* t)
{
// This read was too wide.
return *t;
}

private class EndOfPage : IDisposable
{
private void* _addr;
private EndOfPage()
{
}

public Test* Pointer => (Test*)((byte*)_addr + 0x1000 - sizeof(Test));
public void Dispose()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
const int MEM_RELEASE = 0x8000;
VirtualFree(_addr, 0, MEM_RELEASE);
}
else
{
NativeMemory.Free(_addr);
}
}

public static EndOfPage Create()
{
void* mem;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
const int MEM_COMMIT = 0x1000;
const int MEM_RESERVE = 0x2000;
const int PAGE_READWRITE = 0x04;

// Reserve 2 pages
void* pages = VirtualAlloc(null, 0x2000, MEM_RESERVE, PAGE_READWRITE);
if (pages == null)
{
return null;
}
// Commit first page
mem = VirtualAlloc(pages, 0x1000, MEM_COMMIT, PAGE_READWRITE);
if (mem != pages)
{
return null;
}
}
else
{
try
{
mem = NativeMemory.Alloc(0x1000);
}
catch (OutOfMemoryException)
{
return null;
}
}

return new EndOfPage { _addr = mem };
}

[DllImport("kernel32")]
private static extern void* VirtualAlloc(void* lpAddress, nuint dwSize, uint flAllocationType, uint flProtect);

[DllImport("kernel32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool VirtualFree(void* lpAddress, nuint dwSize, uint dwFreeType);
}
}

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