Skip to content

Commit 60cdc8f

Browse files
Fix Windows x86_64 CI: align CONTEXT to 16 bytes for GetThreadContext/SetThreadContext
Root cause: The windows-sys crate defines CONTEXT with #[repr(C)] which only provides 8-byte natural alignment on x86_64. However, the Windows API documentation states: "The CONTEXT structure must be 16-byte aligned when used with GetThreadContext and SetThreadContext functions." This explains why ALL i686 Windows targets passed (i686 CONTEXT has no 16-byte alignment requirement) while ALL x86_64 Windows targets failed (GetThreadContext/SetThreadContext return 0 on misaligned CONTEXT). Fix: Use a #[repr(C, align(16))] wrapper (AlignedContext) to ensure the CONTEXT struct is properly 16-byte aligned on x86_64. Agent-Logs-Url: https://github.com/acl-dev/open-coroutine/sessions/e3e0796e-c5d6-4538-92c8-b0fe0fd582af Co-authored-by: loongs-zhang <38336731+loongs-zhang@users.noreply.github.com>
1 parent d450196 commit 60cdc8f

1 file changed

Lines changed: 17 additions & 8 deletions

File tree

core/src/monitor.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ impl Monitor {
223223
THREAD_SUSPEND_RESUME,
224224
};
225225

226+
// Windows API requires CONTEXT to be 16-byte aligned for
227+
// GetThreadContext/SetThreadContext on x86_64. The windows-sys crate
228+
// defines CONTEXT with #[repr(C)] (natural alignment 8), which is
229+
// insufficient. This wrapper ensures proper alignment.
230+
#[cfg(target_arch = "x86_64")]
231+
#[repr(C, align(16))]
232+
struct AlignedContext(CONTEXT);
233+
226234
extern "C" {
227235
fn preempt_asm();
228236
}
@@ -242,24 +250,25 @@ impl Monitor {
242250
return false;
243251
}
244252

245-
let mut context: CONTEXT = std::mem::zeroed();
246253
cfg_if::cfg_if! {
247254
if #[cfg(target_arch = "x86_64")] {
248-
// CONTEXT_CONTROL for AMD64: only captures/restores control
255+
let mut aligned = AlignedContext(std::mem::zeroed());
256+
let context = &mut aligned.0;
257+
// CONTEXT_CONTROL for AMD64: captures/restores control
249258
// registers (RIP, RSP, RBP, RFLAGS, segment registers).
250259
// We only need to modify RIP and RSP to redirect the thread
251-
// to preempt_asm. The assembly itself saves and restores all
252-
// other registers (GPRs, XMMs, RFLAGS). Using CONTEXT_FULL
253-
// here would clobber registers that are in-use by the target
254-
// thread, causing SetThreadContext to corrupt thread state.
260+
// to preempt_asm. The assembly saves and restores all other
261+
// registers (GPRs, XMMs, RFLAGS).
255262
context.ContextFlags = 0x0010_0001;
256263
} else if #[cfg(target_arch = "x86")] {
264+
let mut context: CONTEXT = std::mem::zeroed();
265+
let context = &mut context;
257266
// CONTEXT_CONTROL for i386
258267
context.ContextFlags = 0x0001_0001;
259268
}
260269
}
261270

262-
if GetThreadContext(handle, &raw mut context) == 0 {
271+
if GetThreadContext(handle, &raw mut *context) == 0 {
263272
_ = ResumeThread(handle);
264273
_ = CloseHandle(handle);
265274
return false;
@@ -295,7 +304,7 @@ impl Monitor {
295304
}
296305
}
297306

298-
if SetThreadContext(handle, &raw const context) == 0 {
307+
if SetThreadContext(handle, &raw const *context) == 0 {
299308
_ = ResumeThread(handle);
300309
_ = CloseHandle(handle);
301310
return false;

0 commit comments

Comments
 (0)