Skip to content

Unexpected ELT callbacks for ProfilerBeginTransitionCallback and ProfilerEndTransitionCallback #130242

Description

@valco1994

Description

Since .NET 11 preview 4 ProfilerBeginTransitionCallback and ProfilerEndTransitionCallback are reported to profiler via Enter-Leave-Tailcall (ELT) callbacks in profiler. These functions bracket managed-to-unmanaged and unmanaged-to managed transitions and corresponding profiler callbacks (ManagedToUnmanagedTransition and UnmanagedToManagedTransition) and break the consistency of the shadow stack.

As far as I see, these methods are QCalls since the summer 2024. Honestly, I thought that QCalls are not supposed to be reported to profiler via ELT callbacks at all.

I'm not sure, but suspect that it can be caused by PR #126509.

Is it a a bug or a new expected behaviour?

Reproduction Steps

Run any application containing a P/Invoke or reversed P/Invoke using .NET 11 preview 4+ with enabled COR_PRF_MONITOR_ENTERLEAVE flag in the event mask.

I observed the problem on the following application:

using System;
using System.Runtime.InteropServices;

internal static partial class Kernel32
{
  [LibraryImport("kernel32.dll", EntryPoint = "GetFileAttributesW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
  internal static partial uint GetFileAttributes(string fileName);
}

internal static class Program
{
  private static int Main()
  {
    try
    {
      const string fileName = "file-that-should-not-exist.txt";
      Console.WriteLine("[{0}] Create", DateTime.Now);

      var fileNotFound = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
        ? IsFileNotFoundWindows(fileName)
        : IsFileNotFoundLinuxMacOs(fileName);
      Console.WriteLine("[{0}] Check fileNotFound? {1}! fileName {2}", DateTime.Now, fileNotFound, fileName);
      if (!fileNotFound)
        throw new Exception("File-not-found error is expected");

      Console.WriteLine("[{0}] Done", DateTime.Now);
      return 0;
    }
    catch (Exception e)
    {
      Console.Error.WriteLine(e);
      return 1;
    }
  }

  private static bool IsFileNotFoundWindows(string fileName)
  {
    // ReSharper disable InconsistentNaming
    const uint INVALID_FILE_ATTRIBUTES = unchecked((uint)-1);
    const int ERROR_FILE_NOT_FOUND = 2;
    // ReSharper restore InconsistentNaming
    return Kernel32.GetFileAttributes(fileName) == INVALID_FILE_ATTRIBUTES && Marshal.GetLastPInvokeError() == ERROR_FILE_NOT_FOUND;
  }
}

Expected behavior

ProfilerBeginTransitionCallback and ProfilerEndTransitionCallback are not reported to profiler via ELT callbacks

Actual behavior

ProfilerBeginTransitionCallback and ProfilerEndTransitionCallback are reported to profiler via ELT callbacks

Regression?

Yes, ProfilerBeginTransitionCallback and ProfilerEndTransitionCallback were not reported via ELT callbacks before .NET 11 preview 4.

Known Workarounds

It's possible to disable ELT callbacks for these methods using ICorProfilerInfo3::SetFunctionIDMapper2.

Configuration

.NET 11 preview 4+.
Reproduce on Windows, Linux and macOS for me.
It looks like the problem is common for all supported platforms.

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions