Skip to content

[Backport][main to 0.9] | fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720) - #1725

Merged
Coldwings merged 2 commits into
release/0.9from
backport-pr-26e71f7d7680708aee0dc219b63ea53f334ce5bf-0.9
Nov 4, 2026
Merged

Coldwings merged 2 commits into
release/0.9from
backport-pr-26e71f7d7680708aee0dc219b63ea53f334ce5bf-0.9

Conversation

@photonlibos

@photonlibos photonlibos commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720)

  • fix(thread): complete clobbers of context switch, align defer stack, skip red zone

switch_context() / switch_context_defer() hide a function call inside an
asm statement, across which other photon threads run and may change any
register or memory. The clobber lists only named GPRs (plus xmm6-15 on
Win64), so the compiler was free to keep values in vector registers, in
memory it had cached, or in the red zone across a switch.

This is what makes GCC 10/11/12 CI jobs crash (SEGFAULT in test-thread,
test-socket, test-pool, test-executor-std, test-exportfs) on part of the
nodes: with -march=native on a CPU model unknown to these versions (most
likely Emerald Rapids, 0xCF), the driver falls back to -march=cooperlake
-mtune=generic, under which GCC keeps the thread pointer behind
return rq.current->error_number in %xmm0 across the switch in
thread_yield_to().

  • x86_64 / aarch64: declare all vector registers (and AVX-512 opmask /
    SVE predicate registers when enabled) as clobbered, plus "memory";
    plus "cc" on aarch64.
  • x86_64 SysV / Apple arm64: skip the 128-byte red zone before the call,
    as GCC's manual describes for asm containing calls or pushes.
  • x86_64: call the defer function with %rsp aligned to 16 bytes instead
    of jumping into it on whatever the switch-point %rsp happens to be.
  • Win64: reserve the 32-byte shadow space for the defer function and the
    thread entry; the latter otherwise overlaps the head of struct thread.
  • tools/photongdb.py: account for the skipped red zone when recovering
    %rsp of a switched-out thread.
  • fix(thread): clarify why volatile registers must be listed as clobbers

The asm statement is not treated as a call, so the ABI's caller-saved
registers are not implied clobbered; nor does the C++ call of the inline
switch_context() help, as it is inlined, or subject to -fipa-ra.

  • fix(thread): remove speculative red-zone padding

Restore the original saved-stack layout and photongdb offset. Keep vector/memory/cc clobbers, defer alignment and Win64 shadow space; no current Photon red-zone failure has been demonstrated.

  • fix(thread): preserve original defer jump trampolines

  • fix(thread): move Win64 shadow-space comment to _photon_thread_stub
    Generated by Backport Auto PR, by cherry-pick related commits.

Please review and decide whether to merge or close this backport PR.

Conflicts

Cherry-pick produced conflicts. Conflict markers are committed as-is; please resolve them manually before merging.

Conflict resolution

Resolved in a14f89f. The only conflict is the Win64 _photon_thread_stub, where release/0.9 still has call _asan_start (main removed it from the Win64 stub in #937). The resolution keeps the sub $32, %rsp shadow-space reservation from #1720 and drops call _asan_start, so the Win64 stub is now identical to main. ASan builds are Linux-only (PHOTON_BUILD_WITH_ASAN fails the CMake configure on other systems), so on Win64 _asan_start was always an empty function. The SysV and aarch64 stubs are unchanged.

…w space (#1720)

* fix(thread): complete clobbers of context switch, align defer stack, skip red zone

switch_context() / switch_context_defer() hide a function call inside an
asm statement, across which other photon threads run and may change any
register or memory. The clobber lists only named GPRs (plus xmm6-15 on
Win64), so the compiler was free to keep values in vector registers, in
memory it had cached, or in the red zone across a switch.

This is what makes GCC 10/11/12 CI jobs crash (SEGFAULT in test-thread,
test-socket, test-pool, test-executor-std, test-exportfs) on part of the
nodes: with -march=native on a CPU model unknown to these versions (most
likely Emerald Rapids, 0xCF), the driver falls back to -march=cooperlake
-mtune=generic, under which GCC keeps the thread pointer behind
`return rq.current->error_number` in %xmm0 across the switch in
thread_yield_to().

- x86_64 / aarch64: declare all vector registers (and AVX-512 opmask /
  SVE predicate registers when enabled) as clobbered, plus "memory";
  plus "cc" on aarch64.
- x86_64 SysV / Apple arm64: skip the 128-byte red zone before the call,
  as GCC's manual describes for asm containing calls or pushes.
- x86_64: call the defer function with %rsp aligned to 16 bytes instead
  of jumping into it on whatever the switch-point %rsp happens to be.
- Win64: reserve the 32-byte shadow space for the defer function and the
  thread entry; the latter otherwise overlaps the head of `struct thread`.
- tools/photongdb.py: account for the skipped red zone when recovering
  %rsp of a switched-out thread.

* fix(thread): clarify why volatile registers must be listed as clobbers

The asm statement is not treated as a call, so the ABI's caller-saved
registers are not implied clobbered; nor does the C++ call of the inline
switch_context() help, as it is inlined, or subject to -fipa-ra.

* fix(thread): remove speculative red-zone padding

Restore the original saved-stack layout and photongdb offset. Keep vector/memory/cc clobbers, defer alignment and Win64 shadow space; no current Photon red-zone failure has been demonstrated.

* fix(thread): preserve original defer jump trampolines

* fix(thread): move Win64 shadow-space comment to _photon_thread_stub
@photonlibos photonlibos added need-backport A PR that should be back-ported to prior release branches (release/*) needs-manual-merge Auto-PR encounters conflicts and need to be fix manually. labels Nov 2, 2026
Take the 32-byte shadow-space reservation from #1720 and drop the
Win64 call to _asan_start, as main did in #937. ASan builds are
Linux-only (PHOTON_BUILD_WITH_ASAN fails the configure elsewhere),
so on Win64 _asan_start is always an empty function.
@lihuiba
lihuiba marked this pull request as ready for review November 3, 2026 01:29
@Coldwings Coldwings removed the needs-manual-merge Auto-PR encounters conflicts and need to be fix manually. label Nov 4, 2026
@Coldwings
Coldwings merged commit 41728a4 into release/0.9 Nov 4, 2026
30 checks passed
@photonlibos
photonlibos deleted the backport-pr-26e71f7d7680708aee0dc219b63ea53f334ce5bf-0.9 branch November 4, 2026 04:17
lihuiba pushed a commit that referenced this pull request Nov 4, 2026
…rs and reserve Win64 shadow space (#1720) (#1725) (#1726)

* fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720)

* fix(thread): complete clobbers of context switch, align defer stack, skip red zone

switch_context() / switch_context_defer() hide a function call inside an
asm statement, across which other photon threads run and may change any
register or memory. The clobber lists only named GPRs (plus xmm6-15 on
Win64), so the compiler was free to keep values in vector registers, in
memory it had cached, or in the red zone across a switch.

This is what makes GCC 10/11/12 CI jobs crash (SEGFAULT in test-thread,
test-socket, test-pool, test-executor-std, test-exportfs) on part of the
nodes: with -march=native on a CPU model unknown to these versions (most
likely Emerald Rapids, 0xCF), the driver falls back to -march=cooperlake
-mtune=generic, under which GCC keeps the thread pointer behind
`return rq.current->error_number` in %xmm0 across the switch in
thread_yield_to().

- x86_64 / aarch64: declare all vector registers (and AVX-512 opmask /
  SVE predicate registers when enabled) as clobbered, plus "memory";
  plus "cc" on aarch64.
- x86_64 SysV / Apple arm64: skip the 128-byte red zone before the call,
  as GCC's manual describes for asm containing calls or pushes.
- x86_64: call the defer function with %rsp aligned to 16 bytes instead
  of jumping into it on whatever the switch-point %rsp happens to be.
- Win64: reserve the 32-byte shadow space for the defer function and the
  thread entry; the latter otherwise overlaps the head of `struct thread`.
- tools/photongdb.py: account for the skipped red zone when recovering
  %rsp of a switched-out thread.

* fix(thread): clarify why volatile registers must be listed as clobbers

The asm statement is not treated as a call, so the ABI's caller-saved
registers are not implied clobbered; nor does the C++ call of the inline
switch_context() help, as it is inlined, or subject to -fipa-ra.

* fix(thread): remove speculative red-zone padding

Restore the original saved-stack layout and photongdb offset. Keep vector/memory/cc clobbers, defer alignment and Win64 shadow space; no current Photon red-zone failure has been demonstrated.

* fix(thread): preserve original defer jump trampolines

* fix(thread): move Win64 shadow-space comment to _photon_thread_stub

* fix(thread): resolve Win64 thread stub conflict for release/0.9

Take the 32-byte shadow-space reservation from #1720 and drop the
Win64 call to _asan_start, as main did in #937. ASan builds are
Linux-only (PHOTON_BUILD_WITH_ASAN fails the configure elsewhere),
so on Win64 _asan_start is always an empty function.

---------

Co-authored-by: Coldwings <coldwings@me.com>
lihuiba added a commit that referenced this pull request Nov 4, 2026
…ers and reserve Win64 shadow space (#1720) (#1725) (#1726) (#1727)

* [Backport][main to 0.9] | fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720) (#1725) (#1726)

* fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720)

* fix(thread): complete clobbers of context switch, align defer stack, skip red zone

switch_context() / switch_context_defer() hide a function call inside an
asm statement, across which other photon threads run and may change any
register or memory. The clobber lists only named GPRs (plus xmm6-15 on
Win64), so the compiler was free to keep values in vector registers, in
memory it had cached, or in the red zone across a switch.

This is what makes GCC 10/11/12 CI jobs crash (SEGFAULT in test-thread,
test-socket, test-pool, test-executor-std, test-exportfs) on part of the
nodes: with -march=native on a CPU model unknown to these versions (most
likely Emerald Rapids, 0xCF), the driver falls back to -march=cooperlake
-mtune=generic, under which GCC keeps the thread pointer behind
`return rq.current->error_number` in %xmm0 across the switch in
thread_yield_to().

- x86_64 / aarch64: declare all vector registers (and AVX-512 opmask /
  SVE predicate registers when enabled) as clobbered, plus "memory";
  plus "cc" on aarch64.
- x86_64 SysV / Apple arm64: skip the 128-byte red zone before the call,
  as GCC's manual describes for asm containing calls or pushes.
- x86_64: call the defer function with %rsp aligned to 16 bytes instead
  of jumping into it on whatever the switch-point %rsp happens to be.
- Win64: reserve the 32-byte shadow space for the defer function and the
  thread entry; the latter otherwise overlaps the head of `struct thread`.
- tools/photongdb.py: account for the skipped red zone when recovering
  %rsp of a switched-out thread.

* fix(thread): clarify why volatile registers must be listed as clobbers

The asm statement is not treated as a call, so the ABI's caller-saved
registers are not implied clobbered; nor does the C++ call of the inline
switch_context() help, as it is inlined, or subject to -fipa-ra.

* fix(thread): remove speculative red-zone padding

Restore the original saved-stack layout and photongdb offset. Keep vector/memory/cc clobbers, defer alignment and Win64 shadow space; no current Photon red-zone failure has been demonstrated.

* fix(thread): preserve original defer jump trampolines

* fix(thread): move Win64 shadow-space comment to _photon_thread_stub

* fix(thread): resolve Win64 thread stub conflict for release/0.9

Take the 32-byte shadow-space reservation from #1720 and drop the
Win64 call to _asan_start, as main did in #937. ASan builds are
Linux-only (PHOTON_BUILD_WITH_ASAN fails the configure elsewhere),
so on Win64 _asan_start is always an empty function.

---------

Co-authored-by: Coldwings <coldwings@me.com>

* fix(thread): resolve the Win64 thread stub conflict for release/0.7

Take the 32-byte shadow-space reservation from #1720. release/0.7 never
had the Win64 `call _asan_start` that the upstream change replaced, so
there is nothing to drop here.

---------

Co-authored-by: Coldwings <coldwings@me.com>
Co-authored-by: lihuiba <huiba.lhb@alibaba-inc.com>
lihuiba added a commit that referenced this pull request Nov 4, 2026
…ers and reserve Win64 shadow space (#1720) (#1725) (#1726) (#1727) (#1728)

* [Backport][main to 0.9] | fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720) (#1725) (#1726)

* fix(thread): complete context-switch clobbers and reserve Win64 shadow space (#1720)

* fix(thread): complete clobbers of context switch, align defer stack, skip red zone

switch_context() / switch_context_defer() hide a function call inside an
asm statement, across which other photon threads run and may change any
register or memory. The clobber lists only named GPRs (plus xmm6-15 on
Win64), so the compiler was free to keep values in vector registers, in
memory it had cached, or in the red zone across a switch.

This is what makes GCC 10/11/12 CI jobs crash (SEGFAULT in test-thread,
test-socket, test-pool, test-executor-std, test-exportfs) on part of the
nodes: with -march=native on a CPU model unknown to these versions (most
likely Emerald Rapids, 0xCF), the driver falls back to -march=cooperlake
-mtune=generic, under which GCC keeps the thread pointer behind
`return rq.current->error_number` in %xmm0 across the switch in
thread_yield_to().

- x86_64 / aarch64: declare all vector registers (and AVX-512 opmask /
  SVE predicate registers when enabled) as clobbered, plus "memory";
  plus "cc" on aarch64.
- x86_64 SysV / Apple arm64: skip the 128-byte red zone before the call,
  as GCC's manual describes for asm containing calls or pushes.
- x86_64: call the defer function with %rsp aligned to 16 bytes instead
  of jumping into it on whatever the switch-point %rsp happens to be.
- Win64: reserve the 32-byte shadow space for the defer function and the
  thread entry; the latter otherwise overlaps the head of `struct thread`.
- tools/photongdb.py: account for the skipped red zone when recovering
  %rsp of a switched-out thread.

* fix(thread): clarify why volatile registers must be listed as clobbers

The asm statement is not treated as a call, so the ABI's caller-saved
registers are not implied clobbered; nor does the C++ call of the inline
switch_context() help, as it is inlined, or subject to -fipa-ra.

* fix(thread): remove speculative red-zone padding

Restore the original saved-stack layout and photongdb offset. Keep vector/memory/cc clobbers, defer alignment and Win64 shadow space; no current Photon red-zone failure has been demonstrated.

* fix(thread): preserve original defer jump trampolines

* fix(thread): move Win64 shadow-space comment to _photon_thread_stub

* fix(thread): resolve Win64 thread stub conflict for release/0.9

Take the 32-byte shadow-space reservation from #1720 and drop the
Win64 call to _asan_start, as main did in #937. ASan builds are
Linux-only (PHOTON_BUILD_WITH_ASAN fails the configure elsewhere),
so on Win64 _asan_start is always an empty function.

---------



* fix(thread): resolve the Win64 thread stub conflict for release/0.7

Take the 32-byte shadow-space reservation from #1720. release/0.7 never
had the Win64 `call _asan_start` that the upstream change replaced, so
there is nothing to drop here.

---------

Co-authored-by: Coldwings <coldwings@me.com>
Co-authored-by: lihuiba <huiba.lhb@alibaba-inc.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

need-backport A PR that should be back-ported to prior release branches (release/*)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants