dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.98k stars 4.66k forks source link

A JIT bug in rejected VSD tail call processing logic on macOS x64 #47750

Closed aleksandr-urakov closed 3 years ago

aleksandr-urakov commented 3 years ago

Description

Running the following code snippet in release mode on macOS x64 using the master branch of .NET Core:

using System;
using System.Runtime.CompilerServices;
namespace ConsoleApp1
{
    public readonly struct Struct
    {
        public Struct(long a, long b)
        {
            A = a;
            B = b;
        }
        public readonly long A;
        public readonly long B;
    }
    public interface IInterface
    {
        Struct Foo(int x, int y, int z, int a, int b, int c);
    }
    class CClass : IInterface
    {
        public Struct Foo(int x, int y, int z, int a, int b, int c)
        {
            return new(x + y + z, a + b + c);
        }
    }
    public static class Program
    {
        private static Struct Bar(IInterface i, int x)
        {
            return i.Foo(x, x + 1, x + 2, x + 3, x + 4, x + 5);
        }
        [MethodImpl(MethodImplOptions.NoOptimization)]
        static void Main()
        {
            var c = new CClass();
            for (var i = 0; i < 1000000000; i++)
            {
                var s = Bar(c, 1);
                Console.WriteLine(s.A + s.B);
            }
        }
    }
}

The output is following:

21
21
21
...
21
21
21
465043519
465043519
465043519
...

The expected output is:

21
21
21
...
21
21
21

Configuration

I run it on a self-built .NET core from the most actual master branch using macOS 11.1 x64. AFAIK, it isn't reproducible on Windows.

Regression?

The issue is actual for .NET Core 5.0 too, but I'm not sure about earlier versions.

Other information

It looks like the bug is in rejected tail call processing logic during Tier-1 compilation (that's why the sample starts working OK, just like a debug build, using a Tier-0). When a VSD tail call (the call to Foo in the Bar method) is rejected, and it has a multi-register struct return value (Struct in our case), re-evaluation of fgArgInfo (see Compiler::fgMorphCall(...)) leads to duplication of the stub address in the list of arguments. I also attach here the log for sample ran with COMPlus_JitDump="Bar".

output.log

sandreenko commented 3 years ago

that was probably fixed by https://github.com/dotnet/runtime/pull/49256

BruceForstall commented 3 years ago

@aleksandr-urakov Thanks for such a detailed and reduced repro case.

Yes, this is the same bug as the one fixed by #49256 . It will be fixed in the 5.0 servicing branch with https://github.com/dotnet/runtime/pull/49256.

aleksandr-urakov commented 3 years ago

Ok, thanks a lot!