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 <[email protected]>
Co-authored-by: Hannes Domani <[email protected]>
@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?

@mstorsjo mstorsjo changed the title [libunwind] Fix aarch64 unwinding with a debugger attached [libunwind] Fix aarch64 SEH unwinding with a debugger attached Oct 15, 2025
@mstorsjo mstorsjo merged commit a17afee into llvm:main Oct 16, 2025
76 of 79 checks passed
@mstorsjo mstorsjo deleted the libunwind-unwind-ctx branch October 16, 2025 19:47
@mstorsjo mstorsjo added this to the LLVM 21.x Release milestone Oct 16, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Oct 16, 2025
@mstorsjo
Copy link
Member Author

/cherry-pick a17afee

@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2025

/pull-request #163854

@llvmbot llvmbot moved this from Needs Triage to Done in LLVM Release Status Oct 16, 2025
c-rhodes pushed a commit to llvmbot/llvm-project that referenced this pull request Oct 17, 2025
…162867)

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 <[email protected]>
Co-authored-by: Hannes Domani <[email protected]>
(cherry picked from commit a17afee)
alexrp added a commit to alexrp/zig that referenced this pull request Oct 17, 2025
alexrp added a commit to alexrp/zig that referenced this pull request Oct 17, 2025
alexrp added a commit to ziglang/zig that referenced this pull request Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

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