runtime: ExecutionEngineException when using step-by-step
Description
When trying to find the source of an “CancelledOperationException” being thrown in background in my app, I stumbled on a weird bug.
When I step in a specific place, it will throw a ExecutionEngineException
, and if I try to continue the program execution it will freeze VS2022 (and I must kill it with taskmanager).
As I don’t know where the issue come from, I created the issue here.
Reproduction Steps
Clone my repo https://github.com/Kuinox/CK-LogViewer/commit/ac8a94534f510e83c52401cb267a46bd873c94e4 and checkout on the commit linked (it was the develop branch when this issue was opened).
Run LogSampleGenerator
until it hit the Debugger.Break()
.
Now due to this issue: https://github.com/dotnet/sdk/issues/1458, 3 pdb must be loaded by hand in VS, they are located in the nuget cache:
%userprofile%\.nuget\packages\ck.mqtt.abstractions\0.10.0\lib\net6.0
%userprofile%\.nuget\packages\ck.mqtt.common\0.10.0\lib\net6.0
%userprofile%\.nuget\packages\ck.mqtt.client\0.10.0\lib\net6.0
Now navigate to
CK.MQTT.Client.dll!CK.MQTT.SmallOutgoingApplicationMessageExtensions.PublishAsync(CK.MQTT.IMqtt3Client client, CK.Core.IActivityMonitor m, string topic, CK.MQTT.QualityOfService qos, bool retain, System.ReadOnlyMemory<byte> payload) Line 13 C#
CK.Monitoring.MQTT.dll!CK.Monitoring.MQTT.MQTT.DoHandleAsync(CK.Core.IActivityMonitor m, CK.Monitoring.IMulticastLogEntry entry) Line 29 C#
Now trying to step in
SendPacketAsync
throw the ExecutionEngineException
.
Pressing F5/F10 here lead to VS freezing.
Expected behavior
Being able to debug my program.
Actual behavior
An ExecutionEngineException is throwed.
Regression?
I don’t know, new app/code.
Known Workarounds
No response
Configuration
.NET 6.0.1 Windows 11/10
Other information
No response
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 21 (21 by maintainers)
Here is a simplified repro case:
Expected result: execution pauses inside SendPacketAsync() Actual result: VS shows a dialog for an unhandled ExecutionEngineException
Duplicate of https://github.com/dotnet/runtime/issues/38777 ? The proposed fix: https://github.com/dotnet/runtime/issues/38777#issuecomment-655488029
@davidwrighton @AaronRobinsonMSFT @jkoritzinsky - this bug appears to be a long-standing issue with IL stubs, I’m not sure who the owner of that is these days? The short version is that ILStubManager::TraceManager doesn’t appear to correctly handle all the ILStubs that the runtime creates. A few years ago we encountered a very similar problem with a different type of ILStub that this method didn’t handle so this appears to be a repeating problem.
Investigating the dump that @Kuinox sent us, this is the long version of what I think likely has happened:
00007ffae9037c31
and tries to determine where execution will go next.That call at the end will lead to executing the jitted code for the IL instantiating stub for SendPacketAsync<T>(…)
00007ffae9038da0
, an IL instantiating stub:StubManager::TraceStub() determines that the target address belongs to the ILStubManager because ILStubManager::CheckIsStub_Internal claims all addresses that map to MethodDescs where MethodDesc::IsILStub() is TRUE.
StubManager::TraceStub then asks ILStubManager to predict where the stub will execute to by calling ILStubManager::DoTraceStub(). The implementation of this method returns something called “ManagerPush” with the stub start address (
00007ffae9038da0
). This is intended for cases where the stub manager can’t predict the destination of the stub given its IP alone. Instead the StubManager is requesting that the debugger set a breakpoint at the address it returned, then call back to the stub manager later once execution has reached that address. At that point the debugger will be able to provide a complete CONTEXT rather than the IP alone.StubManager code returns back to the debugger, the debugger sets the breakpoint at
00007ffae9038da0
as requested, and returns back through the vectored exception handler which ultimately resumes execution in the jitted user code at00007ffae9037c31
:00007ffae9038da0
and triggering the breakpoint placed by the debugger. This generates an exception that calls back into vectored exception handler and works it way back to the debugger code.I’m pretty sure the bug is right here in the incorrect classification, but execution continues a little further doing calculations based on garbage data…
arg
, the hidden argument, by reading from R10 in the CONTEXT above:0x000001b0e462f170
. pMD = arg pCMD = pMD pCMD->m_pComPlusCallInfo = 00007ffa4f977cc5 As best I understand R10 is not part of the expected calling convention for invoking an instantiating stub so these computations are based on whatever arbitrary value happened to be in the register at the time.The AV occurs at
00007ffb48118e04
which is dereferencing r14+8 =0x00007ffa4f977cc5
+8 =0x00007ffa4f977ccd
Ok, I edited the ticket to remove the link to the uploaded dump.