Skip to content

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

@aleksandr-urakov

Description

@aleksandr-urakov

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

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions