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.
This commit is contained in:
Arun Raghavan 2026-03-10 15:47:29 -07:00 committed by Wim Taymans
parent 0393fd8a72
commit f11ab0da3e

View file

@ -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)