From c35e127a692edaf8f7659e31106b76b34db1e16c Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Thu, 20 Mar 2025 11:15:28 +0100 Subject: [PATCH] AArch64: fiber context switch can segfault We need a store-store barrier between pushing the registers to the current stack and setting the resumable flag of the current fiber, otherwise the CPU is allowed to reorder the instructions at runtime and to store the resumable flag before or while storing the registers. This can happen for example: thread 1: enqueues current fiber A therad 1: swapcontext -> store resumable thread 1: is preempted thread 2: steals fiber A thread 2: resumes fiber A thread 2: loads registers => reads garbage => segfaults thread 1: stores registers (too late) --- src/fiber/context/aarch64-generic.cr | 6 ++++++ src/fiber/context/aarch64-microsoft.cr | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/fiber/context/aarch64-generic.cr b/src/fiber/context/aarch64-generic.cr index 2839ee030ef5..110a8b77aa88 100644 --- a/src/fiber/context/aarch64-generic.cr +++ b/src/fiber/context/aarch64-generic.cr @@ -54,6 +54,9 @@ class Fiber mov x19, sp // current_context.stack_top = sp str x19, [x0, #0] + {% if flag?(:execution_context) %} + dmb ish // barrier: ensure registers are stored + {% end %} mov x19, #1 // current_context.resumable = 1 str x19, [x0, #8] @@ -97,6 +100,9 @@ class Fiber mov x19, sp // current_context.stack_top = sp str x19, [$0, #0] + {% if flag?(:execution_context) %} + dmb ish // barrier: ensure registers are stored + {% end %} mov x19, #1 // current_context.resumable = 1 str x19, [$0, #8] diff --git a/src/fiber/context/aarch64-microsoft.cr b/src/fiber/context/aarch64-microsoft.cr index b9e86dfbc6cf..2d94a64dd36c 100644 --- a/src/fiber/context/aarch64-microsoft.cr +++ b/src/fiber/context/aarch64-microsoft.cr @@ -55,6 +55,9 @@ class Fiber mov x19, sp // current_context.stack_top = sp str x19, [x0, #0] + {% if flag?(:execution_context) %} + dmb ish // barrier: ensure registers are stored + {% end %} mov x19, #1 // current_context.resumable = 1 str x19, [x0, #8] @@ -112,6 +115,9 @@ class Fiber mov x19, sp // current_context.stack_top = sp str x19, [$0, #0] + {% if flag?(:execution_context) %} + dmb ish // barrier: ensure registers are stored + {% end %} mov x19, #1 // current_context.resumable = 1 str x19, [$0, #8]