Files
linux/lib
Marco Elver a21c1e961d compiler: Simplify generic RELOC_HIDE()
When enabling Context Analysis (CONTEXT_ANALYSIS := y) in arch/x86/kvm
code, Clang's Thread Safety Analysis failed to recognize that identical
per_cpu() accesses refer to the same lock:

|   CC [M]  arch/x86/kvm/vmx/posted_intr.o
| arch/x86/kvm/vmx/posted_intr.c:186:2: error: releasing raw_spinlock '__ptr + __per_cpu_offset[vcpu->cpu]' that was not held [-Werror,-Wthread-safety-analysis]
|   186 |         raw_spin_unlock(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu));
|       |         ^
| ./include/linux/spinlock.h:276:32: note: expanded from macro 'raw_spin_unlock'
|   276 | #define raw_spin_unlock(lock)           _raw_spin_unlock(lock)
|       |                                         ^
| arch/x86/kvm/vmx/posted_intr.c:207:1: error: raw_spinlock '__ptr + __per_cpu_offset[vcpu->cpu]' is still held at the end of function [-Werror,-Wthread-safety-analysis]
|   207 | }
|       | ^
| arch/x86/kvm/vmx/posted_intr.c:182:2: note: raw_spinlock acquired here
|   182 |         raw_spin_lock_nested(&per_cpu(wakeup_vcpus_on_cpu_lock, vcpu->cpu),
|       |         ^
| ./include/linux/spinlock.h:235:2: note: expanded from macro 'raw_spin_lock_nested'
|   235 |         _raw_spin_lock(((void)(subclass), (lock)))
|       |         ^
| 2 errors generated.

This occurred because the default RELOC_HIDE() implementation (used by
the per-CPU macros) is a statement expression containing an intermediate
'unsigned long' variable (this version appears to predate Git history).

While the analysis strips away inner casts when resolving pointer
aliases, it stops when encountering intermediate non-pointer variables
(this is Thread Safety Analysis specific and irrelevant for codegen).
This prevents the analysis from concluding that the pointers passed to
e.g. raw_spin_lock() and raw_spin_unlock() were identical when per-CPU
accessors are used.

Simplify RELOC_HIDE() to a single expression. This preserves the intent
of obfuscating UB-introducing out-of-bounds pointer calculations from
the compiler via the 'unsigned long' cast, but allows the alias analysis
to successfully resolve the pointers.

Using a recent Clang version, I observe that generated code remains the
same for vmlinux; the intermediate variable was already being optimized
away (for any respectable modern compiler, not doing so would be an
optimizer bug). Note that GCC provides its own version of RELOC_HIDE(),
so this change only affects Clang builds.

Add a test case to lib/test_context-analysis.c to catch any regressions.

Reported-by: Bart Van Assche <bvanassche@acm.org>
Reported-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Marco Elver <elver@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Link: https://lore.kernel.org/all/e3946223-4543-4a76-a328-9c6865e95192@acm.org/
Link: https://patch.msgid.link/20260319135245.1420780-1-elver@google.com
2026-03-24 15:08:05 +01:00
..
2025-03-16 22:30:49 -07:00
2025-04-11 17:32:37 -07:00
2021-08-19 09:02:55 +09:00
2026-01-11 06:09:11 -10:00
2023-02-02 22:50:01 -08:00
2023-02-02 22:50:01 -08:00
2021-01-03 20:05:18 -05:00
2025-01-12 20:21:15 -08:00
2021-08-19 09:02:55 +09:00
2026-01-26 19:07:13 -08:00
2025-10-24 21:39:27 +02:00
2024-10-14 16:33:24 -05:00
2026-01-11 06:09:11 -10:00
2025-11-27 14:24:30 -08:00
2021-07-08 11:48:20 -07:00
2024-02-15 12:17:28 -05:00
2021-06-18 11:43:09 +02:00
2025-03-25 10:18:31 -03:00
2024-12-09 13:48:29 -08:00
2025-09-13 16:54:46 -07:00