Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native->Managed (.net core) step-in not working in Visual Studio #85339

Closed
johuerta opened this issue Apr 25, 2023 · 6 comments · Fixed by #88683
Closed

Native->Managed (.net core) step-in not working in Visual Studio #85339

johuerta opened this issue Apr 25, 2023 · 6 comments · Fixed by #88683

Comments

@johuerta
Copy link

Description

When interop debugging an app running .net core and stopped at a native frame, attempting to step into a managed function call fails to go into the managed side.

Upon some investigation by us (the vs debugger), it appears that the same scenario in .net framework will send us a step complete event when this step in is requested. We then are able to correctly stop at the right spot on the managed side. In .net core, this event never comes in so we just step over the call to the managed function. We have our stepper use ICorDebugStepper->Step(stepIn:true)

I am unsure if there's some callback we need to provide or some additional setup so that we get notified about the step completion. There is a good chance this is a long-standing issue. Recent efforts to increase our net core interop testing revealed this issue.

This sample app shows the issue happening (open the .sln file)
ConsoleApp1.zip

Reproduction Steps

  • Start in a native frame
  • Step to a call to a managed function
  • Step-in

Expected behavior

Step into managed side works

Actual behavior

We step over the managed function call

Regression?

No response

Known Workarounds

Enabling JMC partially hides this behavior. If the managed function being stepped into is user code, the step in works as expected.

Configuration

.net 6 and .net 8 preview both show this behavior

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Apr 25, 2023
@ghost
Copy link

ghost commented Apr 25, 2023

Tagging subscribers to this area: @tommcdon
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

When interop debugging an app running .net core and stopped at a native frame, attempting to step into a managed function call fails to go into the managed side.

Upon some investigation by us (the vs debugger), it appears that the same scenario in .net framework will send us a step complete event when this step in is requested. We then are able to correctly stop at the right spot on the managed side. In .net core, this event never comes in so we just step over the call to the managed function. We have our stepper use ICorDebugStepper->Step(stepIn:true)

I am unsure if there's some callback we need to provide or some additional setup so that we get notified about the step completion. There is a good chance this is a long-standing issue. Recent efforts to increase our net core interop testing revealed this issue.

This sample app shows the issue happening (open the .sln file)
ConsoleApp1.zip

Reproduction Steps

  • Start in a native frame
  • Step to a call to a managed function
  • Step-in

Expected behavior

Step into managed side works

Actual behavior

We step over the managed function call

Regression?

No response

Known Workarounds

Enabling JMC partially hides this behavior. If the managed function being stepped into is user code, the step in works as expected.

Configuration

.net 6 and .net 8 preview both show this behavior

Other information

No response

Author: johuerta
Assignees: -
Labels:

area-Diagnostics-coreclr

Milestone: -

@hoyosjs hoyosjs added bug and removed untriaged New issue has not been triaged by the area owner labels Apr 25, 2023
@hoyosjs hoyosjs added this to the 8.0.0 milestone Apr 25, 2023
@tommcdon
Copy link
Member

tommcdon commented Jul 9, 2023

@AaronRobinsonMSFT would you be interested in taking a look?

@AaronRobinsonMSFT
Copy link
Member

Enabling JMC partially hides this behavior. If the managed function being stepped into is user code, the step in works as expected.

Yep, the issue is in the StubManager. Scenarios involving UnmanagedCallersOnly always works, but using the classic Delegate approach, with JMC disabled, triggered the following asserts:

Assert failure(PID 14408 [0x00003848], Thread: 4688 [0x1250]): Consistency check failed: Stub at 0x000001F7477DD180 is owner by multiple managers (0x000001F7475FF480, 0x000001F74761BD40)FAILED: (it.Current() == pOwner)

CORECLR! CHECK::Trigger + 0x1E6 (0x00007fff`53ce8ec6)
CORECLR! StubManager::IsSingleOwner + 0x1A2 (0x00007fff`537e4182)
CORECLR! StubManager::TraceStub + 0xC3 (0x00007fff`537e6a73)
CORECLR! EEDbgInterfaceImpl::TraceStub + 0xBA (0x00007fff`53647bea)
CORECLR! DebuggerStepper::TriggerTraceCall + 0xA2 (0x00007fff`53d42fa2)
CORECLR! DebuggerController::DispatchTraceCall + 0x42A (0x00007fff`53d3310a)
CORECLR! Debugger::TraceCall + 0x1F7 (0x00007fff`53d76507)
CORECLR! JIT_ReversePInvokeEnterRare2 + 0xA1 (0x00007fff`539941c1)
CORECLR! JIT_ReversePInvokeEnterTrackTransitions + 0x104 (0x00007fff`53975db4)
<no module>! <no symbol> + 0x0 (0x000001f7`01b59a6b)
    File: ...\runtime\src\coreclr\vm\stubmgr.cpp Line: 396
    Image: ...\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe


Assert failure(PID 14408 [0x00003848], Thread: 4688 [0x1250]): (IsSingleOwner(stubStartAddress, pCurrent))

CORECLR! StubManager::TraceStub + 0xDF (0x00007fff`537e6a8f)
CORECLR! EEDbgInterfaceImpl::TraceStub + 0xBA (0x00007fff`53647bea)
CORECLR! DebuggerStepper::TriggerTraceCall + 0xA2 (0x00007fff`53d42fa2)
CORECLR! DebuggerController::DispatchTraceCall + 0x42A (0x00007fff`53d3310a)
CORECLR! Debugger::TraceCall + 0x1F7 (0x00007fff`53d76507)
CORECLR! JIT_ReversePInvokeEnterRare2 + 0xA1 (0x00007fff`539941c1)
CORECLR! JIT_ReversePInvokeEnterTrackTransitions + 0x104 (0x00007fff`53975db4)
<no module>! <no symbol> + 0x0 (0x000001f7`01b59a6b)
<no module>! <no symbol> + 0x0 (0x0000008a`3377ec78)
<no module>! <no symbol> + 0x0 (0x0000008a`3377ea50)
    File: ...\runtime\src\coreclr\vm\stubmgr.cpp Line: 538
    Image: ...\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe

When stepping into M2() from native code, the above asserts will fire on a checked runtime.

Managed

[UnmanagedCallersOnly]
static void M1()
{
    Console.WriteLine($"Called {nameof(M1)}");
}

delegate void M2Del();

static void M2()
{
    Console.WriteLine($"Called {nameof(M2)}");
}

static void Main(string[] args)
{
    Test_1((delegate* unmanaged<void>)&M1);

    var del = new M2Del(M2);
    Test_1((void*)Marshal.GetFunctionPointerForDelegate(del));
    GC.KeepAlive(del);
}

const string lib = @"NativeLibrary.dll";

[DllImport(lib, EntryPoint = "Test")]
private static extern void* Test_1(void* v);

Native

#define EXPORT_FUNC __declspec(dllexport)
#define CALLCONV __stdcall

extern "C"
{
    using fptr_t = void(CALLCONV*)();

    EXPORT_FUNC void* CALLCONV Test(fptr_t fptr)
    {
        fptr(); // Breakpoint here and step in
        return nullptr;
    }
}

@AaronRobinsonMSFT
Copy link
Member

The conflict is between StubLinkStubManager and DelegateInvokeStubManager.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jul 11, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jul 13, 2023
@AaronRobinsonMSFT
Copy link
Member

@tommcdon The OP states this also occurs in .NET 6. The fix for .NET 8 is rather complicated, but a fix for .NET 6 could be very narrow with minimal risk. Do you have any thoughts about porting a fix for .NET 6?

@tommcdon
Copy link
Member

@tommcdon The OP states this also occurs in .NET 6. The fix for .NET 8 is rather complicated, but a fix for .NET 6 could be very narrow with minimal risk. Do you have any thoughts about porting a fix for .NET 6?

@AaronRobinsonMSFT, this is a great question. I feel that since the issue is partially hidden when JMC is enabled, I feel we should hold until we receive a backport request from a customer.

@ghost ghost locked as resolved and limited conversation to collaborators Aug 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants