Repository navigation
[Profiler] Invalid FunctionID in managed-unmanaged transition in C++/CLI code #120151
Description
Activity
- addeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Sep 26, 2025 - addedneeds-area-labelAn area label is needed to ensure this gets routed to the appropriate area ownersAn area label is needed to ensure this gets routed to the appropriate area owners
on Sep 26, 2025 - added and removedneeds-area-labelAn area label is needed to ensure this gets routed to the appropriate area ownersAn area label is needed to ensure this gets routed to the appropriate area owners
on Sep 26, 2025 dotnet-policy-service commented
on Sep 26, 2025 ContributorMore actionsTagging subscribers to this area: @steveisok, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.- removeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Sep 30, 2025 Is there any update on this? Is this still planned for .NET 11?
I have verified that it's fixed in .NET 11, but repros on .NET 9/10. The fix is a side effect of #117901 and part of that changed the conditions in EmitProfilerBeginTransitionCallback. Previously it misclassified this specific scenario as having a MethodDesc * as the secret argument, but that was not true (its a UMEntryThunkData *) and trying to use that as a MethodDesc * will lead to an AV. In .NET 11 its correctly emitted as NULL, since there is no MethoDesc * for that case. I will see if we could add a regression test covering this scenario, running as part of our profiler tests.
Reacted by andrewimcclement and Mayr PhilippThank you for good news, @lateralusX!
Is there any chance that the fix will be back-ported to .NET 10 and/or 9?Regression test, #131578.
Reacted by andrewimcclementI will look into potential backport to .NET10 (this won't meet the bar for .NET9), but we can't take the full PR, so we will need to backport a more isolated fix, but with the regression test above, it will give us a clear signal if what we backport will be enough to solve the issue.
Reacted by Valentin Grigorev, andrewimcclement and Mayr PhilippThe regression test in #131578 fails on checked build and reveals something interesting that is an artifact of emitting an incorrect internal transition as part of the U2M marshaling stub, reported as an incorrect M2U U2M transition:
000023F8 0 0000000000000000 EProf::UnmanagedToManagedTransition fid=00007FF8A0F87610 reason=call fname='?A0x3e62bc42.func' cname='' --> INCORRECT FORWARD CALL: 000023F8 0 0000000000000000 EProf::ManagedToUnmanagedTransition fid=00007FF8A0FA0000 reason=call // invalid FunctionID --> INCORRECT FORWARD RETURN: 000023F8 0 0000000000000000 EProf::UnmanagedToManagedTransition fid=00007FF8A0FA0000 reason=return // invalid FunctionID 000023F8 0 0000000000000000 EProf::ManagedToUnmanagedTransition fid=00007FF8A0F87610 reason=return fname='?A0x3e62bc42.func' cname=''This was partly fixed in #69761, but didn't include the reverse p/invoke scenario hit by the C++/CLI scenario. I'm tempted to eliminate that incorrectly reported transition altogether, inline with the intent of #69761, but it will be an observable change.
Since the incorrect transition pair previously included an invalid MethodDesc address, that if used would crash the process, I'm leaning towards eliminating the incorrect transitions in .NET11 (instead of keeping it with a NULL function id), even if it would lead to an observable change.
With the change the regression test, that does a M2U (forward p/invoke) then a U2M (reverse p/invoke):
__declspec(noinline) void ManagedByPointerTarget() {} __declspec(noinline) static void call(void (*f)()) { f(); } public ref class TestClass { public: // Managed -> native 'call' -> managed 'ManagedByPointerTarget' by pointer. int CallManagedFunctionByPointer() { call(ManagedByPointerTarget); return 100; } };now ends up emitting:
ManagedToUnmanagedTransition FunctionID=0x0 reason=0 insideTarget=0 name=<null> ← forward calli to native 'call' UnmanagedToManagedTransition FunctionID=0x…4F210 reason=0 insideTarget=0 name=ManagedByPointerTarget ← reverse p/invoke ManagedToUnmanagedTransition FunctionID=0x…4F210 reason=1 insideTarget=1 name=ManagedByPointerTarget ← reverse p/invoke RETURN UnmanagedToManagedTransition FunctionID=0x0 reason=1 insideTarget=0 name=<null> ← forward calli RETURNI will update the regression test PR to include this change (making it into a fix + test PR), if anyone have concerns around doing that change, please let me know.
.NET 10 backport PR, #131928.
Reacted by andrewimcclement and alexanderqqqReacted by Valentin Grigorev- added a commit that references this issue
on Aug 7, 2026 - locked and limited conversation to collaborators
on Sep 6, 2026
Hi there,
Profiler receives invalid FunctionID in manaded-unmanaged transitions callbacks starting from .NET 7 when profiled C++/CLI application calls native function by pointer.
In .NET 6 profiler receives each callback twice, but FunctionID is the same and is correct.
.NET 6.0.36 x64, Windows 24H2 x64 26100.6584:
Starting from .NET 8 (.NET7 we got crash inside dotnet runtime even before
ManagedToUnmanagedTransitioncall) these two additional callback are called with corrupted FunctionID. Using this ID inICorProfilerInfo::GetFunctionInfoor any other method leads to crash (access violation).NET 8.0.20/9.0.9 x64, Windows 24H2 x64 26100.6584:
Here is the sample of C++/CLI the application
CppCliIssue.zip