From f11ab0da3e500ab6f3c9531696bfc67370752550 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Tue, 10 Mar 2026 15:47:29 -0700 Subject: [PATCH] spa: loop: Mark cancellation fields as volatile Cancellation handlers use setjmp/longjmp, for which the C99 specification has the following note: > 17.3.2.1 (3) > All accessible objects have values, and all other components of the > abstract machine) have state, as of the time the longjmp function was > called, except that the values of objects of automatic storage > duration that are local to the function containing the invocation of > the corresponding setjmp macro that do not have volatile-qualified > type and have been changed between the setjmp invocation and longjmp > call are indeterminate. While everything works fine with GCC, with Clang we see that the cancellation handler doesn't seem to have an effect (loop-test fails when it notices that its spa_source's priv and mask have not been cleaned up). The underlying cause is that the compiler can assume data.ep_count is only used in loop_iterate_cancel(), and so can be cached in a register. When we access that field in the cancellation handler, it was never actually written to the memory on the stack, so the read in cancellation_handler() does not see the current value. We fix this by marking all fields on the stack that we expect to be modified in loop_iterate_cancel() as volatile, forcing the memory to be updated and correctly available to the cancellation handler. --- spa/plugins/support/loop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index 1ec2b21c2..5e35f6dcd 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -728,10 +728,10 @@ static int loop_accept(void *object) struct cancellation_handler_data { struct impl *impl; - struct spa_poll_event *ep; - int ep_count; - int unlocked; - int locked; + const struct spa_poll_event *ep; + volatile int ep_count; + volatile int unlocked; + volatile int locked; }; static void cancellation_handler(void *closure)