Skip to content

Conversation

mstorsjo
Copy link
Member

See LuaJIT/LuaJIT#593 (comment) for the original explanation of the problem.

In short; when a debugger is attached, there's a
function KiUserExceptionDispatcher in the stack that is being unwound. The function KiUserExceptionDispatcher contains a CONTEXT, with a copy of the context from where the exception was raised. When unwinding through this function, this whole CONTEXT gets restored.

This CONTEXT is what we receive a pointer to in the callbacks, as the ms_ctx pointer.

When we unwind manually using RtlUnwindEx, the unwinding overwrites the CONTEXT that is passed to it. Thus, to avoid clobbering the CONTEXT that needs to be restored by KiUserExceptionDispatcher, we could either declare a new temporary CONTEXT on the stack before calling RtlUnwindEx, or just use disp->ContextRecord as we already have available.

Fixes: #161851

@mstorsjo mstorsjo requested a review from cjacek October 10, 2025 15:20
@mstorsjo mstorsjo requested a review from a team as a code owner October 10, 2025 15:20
@llvmbot
Copy link
Member

llvmbot commented Oct 10, 2025

@llvm/pr-subscribers-libunwind

Author: Martin Storsjö (mstorsjo)

Changes

See LuaJIT/LuaJIT#593 (comment) for the original explanation of the problem.

In short; when a debugger is attached, there's a
function KiUserExceptionDispatcher in the stack that is being unwound. The function KiUserExceptionDispatcher contains a CONTEXT, with a copy of the context from where the exception was raised. When unwinding through this function, this whole CONTEXT gets restored.

This CONTEXT is what we receive a pointer to in the callbacks, as the ms_ctx pointer.

When we unwind manually using RtlUnwindEx, the unwinding overwrites the CONTEXT that is passed to it. Thus, to avoid clobbering the CONTEXT that needs to be restored by KiUserExceptionDispatcher, we could either declare a new temporary CONTEXT on the stack before calling RtlUnwindEx, or just use disp->ContextRecord as we already have available.

Fixes: #161851


Full diff: https://github.com/llvm/llvm-project/pull/162867.diff

1 Files Affected:

  • (modified) libunwind/src/Unwind-seh.cpp (+1-1)
diff --git a/libunwind/src/Unwind-seh.cpp b/libunwind/src/Unwind-seh.cpp
index 8b83f10615f22..058369acf3360 100644
--- a/libunwind/src/Unwind-seh.cpp
+++ b/libunwind/src/Unwind-seh.cpp
@@ -174,7 +174,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
     }
     // FIXME: Indicate target frame in foreign case!
     // phase 2: the clean up phase
-    RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable);
+    RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, disp->ContextRecord, disp->HistoryTable);
     _LIBUNWIND_ABORT("RtlUnwindEx() failed");
   case _URC_INSTALL_CONTEXT: {
     // If we were called by __libunwind_seh_personality(), indicate that

@mstorsjo
Copy link
Member Author

CC @cdavis5e @ssaba @corsix

I tried to summarize the issue and the fix to the best of my ability in the PR description/commit message - does it seem correct?

Copy link

github-actions bot commented Oct 10, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

See LuaJIT/LuaJIT#593 (comment)
for the original explanation of the problem.

In short; when a debugger is attached, there's a
function KiUserExceptionDispatcher in the stack that is being
unwound. The function KiUserExceptionDispatcher contains
a CONTEXT, with a copy of the context from where the exception
was raised. When unwinding through this function, this
whole CONTEXT gets restored.

This CONTEXT is what we receive a pointer to in the callbacks,
as the ms_ctx pointer.

When we unwind manually using RtlUnwindEx, the unwinding
overwrites the CONTEXT that is passed to it. Thus, to avoid
clobbering the CONTEXT that needs to be restored by
KiUserExceptionDispatcher, we could either declare a new
temporary CONTEXT on the stack before calling RtlUnwindEx,
or just use disp->ContextRecord as we already have
available.

Fixes: llvm#161851

Co-authored-by: Peter Cawley <corsix@corsix.org>
Co-authored-by: Hannes Domani <ssbssa@yahoo.de>
@mstorsjo mstorsjo force-pushed the libunwind-unwind-ctx branch from 3325101 to 7416b04 Compare October 10, 2025 15:33
Copy link
Contributor

@cjacek cjacek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@cdavis5e cdavis5e left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me.

@mstorsjo
Copy link
Member Author

@llvm/reviewers-libunwind - Can I have a code owner approval here, or is it ok to merge this without one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can't debug windows aarch64 executables that throw c++ exceptions, if built with lllvm-mingw

4 participants