From eb85e616a3867944992234f2a0444f1b4e27bfd1 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Tue, 28 Apr 2026 01:23:57 +0200 Subject: [PATCH] Fix interpreter context after breakpoint When debugger breakpoint is hit and then debugger resumes the execution, the context at which the breakpoint was hit can be modified. For example, one of the exception interception tests does that to continue from a different location after an exception is hit. The interpreter ignored changes in the context and resumed execution at the original breakpoint location instead of the modified context. This change fixes it by throwing the ResumeAfterCatchException if the context was modified. That ensures that we resume the exception correctly even if both the stack frame and the ip was changed. The ResumeAfterCatchException became a bit of a misnomer, but I don't want to pollute this PR by renaming the ResumeAfterCatchException to ResumeException, which would be a better name. I'd prefer doing it in a separate PR. --- src/coreclr/vm/interpexec.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index d36bb50efde8d6..d89ae68d123d6f 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -783,11 +783,17 @@ static void InterpBreakpoint(const int32_t *ip, const InterpMethodContextFrame * (void*)GetSP(&ctx), (void*)GetFP(&ctx))); - g_pDebugInterface->FirstChanceNativeException( + if (g_pDebugInterface->FirstChanceNativeException( &exceptionRecord, &ctx, STATUS_BREAKPOINT, - pThread); + pThread)) + { + if ((GetIP(&ctx) != (PCODE)ip) || (GetSP(&ctx) != (DWORD64)pFrame)) + { + ThrowResumeAfterCatchException(GetSP(&ctx), GetIP(&ctx)); + } + } } } #endif // DEBUGGING_SUPPORTED