diff options
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/arm64/include/asm/rwonce.h | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/arch/arm64/include/asm/rwonce.h b/arch/arm64/include/asm/rwonce.h index fc0fb42b0b64..0f3a01d30f66 100644 --- a/arch/arm64/include/asm/rwonce.h +++ b/arch/arm64/include/asm/rwonce.h @@ -20,6 +20,17 @@ ARM64_HAS_LDAPR) /* + * Replace this with typeof_unqual() when minimum compiler versions are + * increased to GCC 14 and Clang 19. For the time being, we need this + * workaround, which relies on function return values dropping qualifiers. + */ +#define __rwonce_typeof_unqual(x) typeof(({ \ + __diag_push() \ + __diag_ignore_all("-Wignored-qualifiers", "") \ + ((typeof(x)(*)(void))0)(); \ + __diag_pop() })) + +/* * When building with LTO, there is an increased risk of the compiler * converting an address dependency headed by a READ_ONCE() invocation * into a control dependency and consequently allowing for harmful @@ -31,9 +42,12 @@ */ #define __READ_ONCE(x) \ ({ \ - typeof(&(x)) __x = &(x); \ - int atomic = 1; \ - union { __unqual_scalar_typeof(*__x) __val; char __c[1]; } __u; \ + auto __x = &(x); \ + auto __ret = (__rwonce_typeof_unqual(*__x) *)__x; \ + /* Hides alias reassignment from Clang's -Wthread-safety. */ \ + auto __retp = &__ret; \ + union { typeof(*__ret) __val; char __c[1]; } __u; \ + *__retp = &__u.__val; \ switch (sizeof(x)) { \ case 1: \ asm volatile(__LOAD_RCPC(b, %w0, %1) \ @@ -56,9 +70,9 @@ : "Q" (*__x) : "memory"); \ break; \ default: \ - atomic = 0; \ + __u.__val = *(volatile typeof(*__x) *)__x; \ } \ - atomic ? (typeof(*__x))__u.__val : (*(volatile typeof(*__x) *)__x);\ + *__ret; \ }) #endif /* !BUILD_VDSO */ |
