linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: Marco Elver <elver@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>,
	Boqun Feng <boqun.feng@gmail.com>,
	 Ingo Molnar <mingo@kernel.org>, Will Deacon <will@kernel.org>,
	 "David S. Miller" <davem@davemloft.net>,
	Luc Van Oostenryck <luc.vanoostenryck@gmail.com>,
	 "Paul E. McKenney" <paulmck@kernel.org>,
	Alexander Potapenko <glider@google.com>,
	Arnd Bergmann <arnd@arndb.de>,
	 Bart Van Assche <bvanassche@acm.org>,
	Bill Wendling <morbo@google.com>, Christoph Hellwig <hch@lst.de>,
	 Dmitry Vyukov <dvyukov@google.com>,
	Eric Dumazet <edumazet@google.com>,
	 Frederic Weisbecker <frederic@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	 Herbert Xu <herbert@gondor.apana.org.au>,
	Jann Horn <jannh@google.com>,
	 Joel Fernandes <joelagnelf@nvidia.com>,
	Jonathan Corbet <corbet@lwn.net>,
	 Josh Triplett <josh@joshtriplett.org>,
	Justin Stitt <justinstitt@google.com>,
	 Kees Cook <kees@kernel.org>,
	Kentaro Takeda <takedakn@nttdata.co.jp>,
	 Lukas Bulwahn <lukas.bulwahn@gmail.com>,
	Mark Rutland <mark.rutland@arm.com>,
	 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Miguel Ojeda <ojeda@kernel.org>,
	 Nathan Chancellor <nathan@kernel.org>,
	Neeraj Upadhyay <neeraj.upadhyay@kernel.org>,
	 Nick Desaulniers <nick.desaulniers+lkml@gmail.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	 Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>,
	Thomas Gleixner <tglx@linutronix.de>,
	 Thomas Graf <tgraf@suug.ch>, Uladzislau Rezki <urezki@gmail.com>,
	Waiman Long <longman@redhat.com>,
	 kasan-dev@googlegroups.com, linux-crypto@vger.kernel.org,
	 linux-doc@vger.kernel.org, linux-kbuild@vger.kernel.org,
	 linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	 linux-security-module@vger.kernel.org,
	linux-sparse@vger.kernel.org,  llvm@lists.linux.dev,
	rcu@vger.kernel.org
Subject: Re: [PATCH v3 02/35] compiler-capability-analysis: Add infrastructure for Clang's capability analysis
Date: Thu, 18 Sep 2025 08:58:24 -0700	[thread overview]
Message-ID: <CAP-5=fUfbMAKrLC_z04o9r0kGZ02tpHfv8cOecQAQaYPx44awA@mail.gmail.com> (raw)
In-Reply-To: <20250918140451.1289454-3-elver@google.com>

On Thu, Sep 18, 2025 at 7:05 AM Marco Elver <elver@google.com> wrote:
>
> Capability analysis is a C language extension, which enables statically
> checking that user-definable "capabilities" are acquired and released where
> required. An obvious application is lock-safety checking for the kernel's
> various synchronization primitives (each of which represents a "capability"),
> and checking that locking rules are not violated.
>
> Clang originally called the feature "Thread Safety Analysis" [1], with
> some terminology still using the thread-safety-analysis-only names. This
> was later changed and the feature became more flexible, gaining the
> ability to define custom "capabilities". Its foundations can be found in
> "capability systems", used to specify the permissibility of operations
> to depend on some capability being held (or not held).
>
> [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
> [2] https://www.cs.cornell.edu/talc/papers/capabilities.pdf
>
> Because the feature is not just able to express capabilities related to
> synchronization primitives, the naming chosen for the kernel departs
> from Clang's initial "Thread Safety" nomenclature and refers to the
> feature as "Capability Analysis" to avoid confusion. The implementation
> still makes references to the older terminology in some places, such as
> `-Wthread-safety` being the warning enabled option that also still
> appears in diagnostic messages.
>
> See more details in the kernel-doc documentation added in this and the
> subsequent changes.
>
> Clang version 22+ is required.
>
> Signed-off-by: Marco Elver <elver@google.com>
> ---
> v3:
> * Require Clang 22 or later (reentrant capabilities, basic alias analysis).
> * Rename __assert_cap/__asserts_cap -> __assume_cap/__assumes_cap (suggested by Peter).
> * Add __acquire_ret and __acquire_shared_ret helper macros - can be used
>   to define function-like macros that return objects which contains a
>   held capabilities. Works now because of capability alias analysis.
> * Add capability_unsafe_alias() helper, where the analysis rightfully
>   points out we're doing strange things with aliases but we don't care.
> * Support multi-argument attributes.
>
> v2:
> * New -Wthread-safety feature rename to -Wthread-safety-pointer (was
>   -Wthread-safety-addressof).
> * Introduce __capability_unsafe() function attribute.
> * Rename __var_guarded_by to simply __guarded_by. The initial idea was
>   to be explicit if the variable or pointed-to data is guarded by, but
>   having a shorter attribute name is likely better long-term.
> * Rename __ref_guarded_by to __pt_guarded_by (pointed-to guarded by).
> ---
>  Makefile                                     |   1 +
>  include/linux/compiler-capability-analysis.h | 449 ++++++++++++++++++-
>  lib/Kconfig.debug                            |  31 ++
>  scripts/Makefile.capability-analysis         |   7 +
>  scripts/Makefile.lib                         |  10 +
>  5 files changed, 491 insertions(+), 7 deletions(-)
>  create mode 100644 scripts/Makefile.capability-analysis
>
> diff --git a/Makefile b/Makefile
> index cf37b9407821..2c91730e513b 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1096,6 +1096,7 @@ include-$(CONFIG_RANDSTRUCT)      += scripts/Makefile.randstruct
>  include-$(CONFIG_KSTACK_ERASE) += scripts/Makefile.kstack_erase
>  include-$(CONFIG_AUTOFDO_CLANG)        += scripts/Makefile.autofdo
>  include-$(CONFIG_PROPELLER_CLANG)      += scripts/Makefile.propeller
> +include-$(CONFIG_WARN_CAPABILITY_ANALYSIS) += scripts/Makefile.capability-analysis
>  include-$(CONFIG_GCC_PLUGINS)  += scripts/Makefile.gcc-plugins
>
>  include $(addprefix $(srctree)/, $(include-y))
> diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/compiler-capability-analysis.h
> index 7546ddb83f86..6f3f185478bc 100644
> --- a/include/linux/compiler-capability-analysis.h
> +++ b/include/linux/compiler-capability-analysis.h
> @@ -6,27 +6,462 @@
>  #ifndef _LINUX_COMPILER_CAPABILITY_ANALYSIS_H
>  #define _LINUX_COMPILER_CAPABILITY_ANALYSIS_H
>
> +#if defined(WARN_CAPABILITY_ANALYSIS)
> +
> +/*
> + * The below attributes are used to define new capability types. Internal only.
> + */
> +# define __cap_type(name)                      __attribute__((capability(#name)))
> +# define __reentrant_cap                       __attribute__((reentrant_capability))
> +# define __acquires_cap(...)                   __attribute__((acquire_capability(__VA_ARGS__)))
> +# define __acquires_shared_cap(...)            __attribute__((acquire_shared_capability(__VA_ARGS__)))
> +# define __try_acquires_cap(ret, var)          __attribute__((try_acquire_capability(ret, var)))
> +# define __try_acquires_shared_cap(ret, var)   __attribute__((try_acquire_shared_capability(ret, var)))
> +# define __releases_cap(...)                   __attribute__((release_capability(__VA_ARGS__)))
> +# define __releases_shared_cap(...)            __attribute__((release_shared_capability(__VA_ARGS__)))
> +# define __assumes_cap(...)                    __attribute__((assert_capability(__VA_ARGS__)))
> +# define __assumes_shared_cap(...)             __attribute__((assert_shared_capability(__VA_ARGS__)))
> +# define __returns_cap(var)                    __attribute__((lock_returned(var)))
> +
> +/*
> + * The below are used to annotate code being checked. Internal only.
> + */
> +# define __excludes_cap(...)           __attribute__((locks_excluded(__VA_ARGS__)))
> +# define __requires_cap(...)           __attribute__((requires_capability(__VA_ARGS__)))
> +# define __requires_shared_cap(...)    __attribute__((requires_shared_capability(__VA_ARGS__)))
> +
> +/**
> + * __guarded_by - struct member and globals attribute, declares variable
> + *                protected by capability
> + *
> + * Declares that the struct member or global variable must be guarded by the
> + * given capabilities. Read operations on the data require shared access,
> + * while write operations require exclusive access.
> + *
> + * .. code-block:: c
> + *
> + *     struct some_state {
> + *             spinlock_t lock;
> + *             long counter __guarded_by(&lock);
> + *     };
> + */
> +# define __guarded_by(...)             __attribute__((guarded_by(__VA_ARGS__)))
> +
> +/**
> + * __pt_guarded_by - struct member and globals attribute, declares pointed-to
> + *                   data is protected by capability
> + *
> + * Declares that the data pointed to by the struct member pointer or global
> + * pointer must be guarded by the given capabilities. Read operations on the
> + * data require shared access, while write operations require exclusive access.
> + *
> + * .. code-block:: c
> + *
> + *     struct some_state {
> + *             spinlock_t lock;
> + *             long *counter __pt_guarded_by(&lock);
> + *     };
> + */
> +# define __pt_guarded_by(...)          __attribute__((pt_guarded_by(__VA_ARGS__)))
> +
> +/**
> + * struct_with_capability() - declare or define a capability struct
> + * @name: struct name
> + *
> + * Helper to declare or define a struct type with capability of the same name.
> + *
> + * .. code-block:: c
> + *
> + *     struct_with_capability(my_handle) {
> + *             int foo;
> + *             long bar;
> + *     };
> + *
> + *     struct some_state {
> + *             ...
> + *     };
> + *     // ... declared elsewhere ...
> + *     struct_with_capability(some_state);
> + *
> + * Note: The implementation defines several helper functions that can acquire,
> + * release, and assert the capability.
> + */
> +# define struct_with_capability(name, ...)                                                             \
> +       struct __cap_type(name) __VA_ARGS__ name;                                                       \
> +       static __always_inline void __acquire_cap(const struct name *var)                               \
> +               __attribute__((overloadable)) __no_capability_analysis __acquires_cap(var) { }          \
> +       static __always_inline void __acquire_shared_cap(const struct name *var)                        \
> +               __attribute__((overloadable)) __no_capability_analysis __acquires_shared_cap(var) { }   \
> +       static __always_inline bool __try_acquire_cap(const struct name *var, bool ret)                 \
> +               __attribute__((overloadable)) __no_capability_analysis __try_acquires_cap(1, var)       \
> +       { return ret; }                                                                                 \
> +       static __always_inline bool __try_acquire_shared_cap(const struct name *var, bool ret)          \
> +               __attribute__((overloadable)) __no_capability_analysis __try_acquires_shared_cap(1, var) \
> +       { return ret; }                                                                                 \
> +       static __always_inline void __release_cap(const struct name *var)                               \
> +               __attribute__((overloadable)) __no_capability_analysis __releases_cap(var) { }          \
> +       static __always_inline void __release_shared_cap(const struct name *var)                        \
> +               __attribute__((overloadable)) __no_capability_analysis __releases_shared_cap(var) { }   \
> +       static __always_inline void __assume_cap(const struct name *var)                                \
> +               __attribute__((overloadable)) __assumes_cap(var) { }                                    \
> +       static __always_inline void __assume_shared_cap(const struct name *var)                         \
> +               __attribute__((overloadable)) __assumes_shared_cap(var) { }                             \
> +       struct name
> +
> +/**
> + * disable_capability_analysis() - disables capability analysis
> + *
> + * Disables capability analysis. Must be paired with a later
> + * enable_capability_analysis().
> + */
> +# define disable_capability_analysis()                         \
> +       __diag_push();                                          \
> +       __diag_ignore_all("-Wunknown-warning-option", "")       \
> +       __diag_ignore_all("-Wthread-safety", "")                \
> +       __diag_ignore_all("-Wthread-safety-pointer", "")
> +
> +/**
> + * enable_capability_analysis() - re-enables capability analysis
> + *
> + * Re-enables capability analysis. Must be paired with a prior
> + * disable_capability_analysis().
> + */
> +# define enable_capability_analysis() __diag_pop()
> +
> +/**
> + * __no_capability_analysis - function attribute, disables capability analysis
> + *
> + * Function attribute denoting that capability analysis is disabled for the
> + * whole function. Prefer use of `capability_unsafe()` where possible.
> + */
> +# define __no_capability_analysis      __attribute__((no_thread_safety_analysis))
> +
> +#else /* !WARN_CAPABILITY_ANALYSIS */
> +
> +# define __cap_type(name)
> +# define __reentrant_cap
> +# define __acquires_cap(...)
> +# define __acquires_shared_cap(...)
> +# define __try_acquires_cap(ret, var)
> +# define __try_acquires_shared_cap(ret, var)
> +# define __releases_cap(...)
> +# define __releases_shared_cap(...)
> +# define __assumes_cap(...)
> +# define __assumes_shared_cap(...)
> +# define __returns_cap(var)
> +# define __guarded_by(...)
> +# define __pt_guarded_by(...)
> +# define __excludes_cap(...)
> +# define __requires_cap(...)
> +# define __requires_shared_cap(...)
> +# define __acquire_cap(var)                    do { } while (0)
> +# define __acquire_shared_cap(var)             do { } while (0)
> +# define __try_acquire_cap(var, ret)           (ret)
> +# define __try_acquire_shared_cap(var, ret)    (ret)
> +# define __release_cap(var)                    do { } while (0)
> +# define __release_shared_cap(var)             do { } while (0)
> +# define __assume_cap(var)                     do { (void)(var); } while (0)
> +# define __assume_shared_cap(var)              do { (void)(var); } while (0)
> +# define struct_with_capability(name, ...)     struct __VA_ARGS__ name
> +# define disable_capability_analysis()
> +# define enable_capability_analysis()
> +# define __no_capability_analysis
> +
> +#endif /* WARN_CAPABILITY_ANALYSIS */
> +
> +/**
> + * capability_unsafe() - disable capability checking for contained code
> + *
> + * Disables capability checking for contained statements or expression.
> + *
> + * .. code-block:: c
> + *
> + *     struct some_data {
> + *             spinlock_t lock;
> + *             int counter __guarded_by(&lock);
> + *     };
> + *
> + *     int foo(struct some_data *d)
> + *     {
> + *             // ...
> + *             // other code that is still checked ...
> + *             // ...
> + *             return capability_unsafe(d->counter);
> + *     }
> + */
> +#define capability_unsafe(...)         \
> +({                                     \
> +       disable_capability_analysis();  \
> +       __VA_ARGS__;                    \
> +       enable_capability_analysis()    \
> +})
> +
> +/**
> + * __capability_unsafe() - function attribute, disable capability checking
> + * @comment: comment explaining why opt-out is safe
> + *
> + * Function attribute denoting that capability analysis is disabled for the
> + * whole function. Forces adding an inline comment as argument.
> + */
> +#define __capability_unsafe(comment) __no_capability_analysis
> +
> +/**
> + * capability_unsafe_alias() - helper to insert a capability "alias barrier"
> + * @p: pointer aliasing a capability or object containing capabilities
> + *
> + * No-op function that acts as a "capability alias barrier", where the analysis
> + * rightfully detects that we're switching aliases, but the switch is considered
> + * safe but beyond the analysis reasoning abilities.
> + *
> + * This should be inserted before the first use of such an alias.
> + *
> + * Implementation Note: The compiler ignores aliases that may be reassigned but
> + * their value cannot be determined (e.g. when passing a non-const pointer to an
> + * alias as a function argument).
> + */
> +#define capability_unsafe_alias(p) _capability_unsafe_alias((void **)&(p))
> +static inline void _capability_unsafe_alias(void **p) { }
> +
> +/**
> + * token_capability() - declare an abstract global capability instance
> + * @name: token capability name
> + *
> + * Helper that declares an abstract global capability instance @name that can be
> + * used as a token capability, but not backed by a real data structure (linker
> + * error if accidentally referenced). The type name is `__capability_@name`.
> + */
> +#define token_capability(name, ...)                                    \
> +       struct_with_capability(__capability_##name, ##__VA_ARGS__) {};  \
> +       extern const struct __capability_##name *name
> +
> +/**
> + * token_capability_instance() - declare another instance of a global capability
> + * @cap: token capability previously declared with token_capability()
> + * @name: name of additional global capability instance
> + *
> + * Helper that declares an additional instance @name of the same token
> + * capability class @name. This is helpful where multiple related token
> + * capabilities are declared, as it also allows using the same underlying type
> + * (`__capability_@cap`) as function arguments.
> + */
> +#define token_capability_instance(cap, name)           \
> +       extern const struct __capability_##cap *name
> +
> +/*
> + * Common keywords for static capability analysis. Both Clang's capability
> + * analysis and Sparse's context tracking are currently supported.
> + */
>  #ifdef __CHECKER__
>
>  /* Sparse context/lock checking support. */
>  # define __must_hold(x)                __attribute__((context(x,1,1)))
> +# define __must_not_hold(x)
>  # define __acquires(x)         __attribute__((context(x,0,1)))
>  # define __cond_acquires(x)    __attribute__((context(x,0,-1)))
>  # define __releases(x)         __attribute__((context(x,1,0)))
>  # define __acquire(x)          __context__(x,1)
>  # define __release(x)          __context__(x,-1)
>  # define __cond_lock(x, c)     ((c) ? ({ __acquire(x); 1; }) : 0)
> +/* For Sparse, there's no distinction between exclusive and shared locks. */
> +# define __must_hold_shared    __must_hold
> +# define __acquires_shared     __acquires
> +# define __cond_acquires_shared __cond_acquires
> +# define __releases_shared     __releases
> +# define __acquire_shared      __acquire
> +# define __release_shared      __release
> +# define __cond_lock_shared    __cond_acquire
>
>  #else /* !__CHECKER__ */
>
> -# define __must_hold(x)
> -# define __acquires(x)
> -# define __cond_acquires(x)
> -# define __releases(x)
> -# define __acquire(x)          (void)0
> -# define __release(x)          (void)0
> -# define __cond_lock(x, c)     (c)
> +/**
> + * __must_hold() - function attribute, caller must hold exclusive capability
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the caller must hold the given capability
> + * instance @x exclusively.
> + */
> +# define __must_hold(x)                __requires_cap(x)
> +
> +/**
> + * __must_not_hold() - function attribute, caller must not hold capability
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the caller must not hold the given
> + * capability instance @x.
> + */
> +# define __must_not_hold(x)    __excludes_cap(x)
> +
> +/**
> + * __acquires() - function attribute, function acquires capability exclusively
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function acquires the given
> + * capability instance @x exclusively, but does not release it.
> + */
> +# define __acquires(x)         __acquires_cap(x)
> +
> +/**
> + * __cond_acquires() - function attribute, function conditionally
> + *                     acquires a capability exclusively
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function conditionally acquires the
> + * given capability instance @x exclusively, but does not release it.
> + */
> +# define __cond_acquires(x)    __try_acquires_cap(1, x)
> +
> +/**
> + * __releases() - function attribute, function releases a capability exclusively
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function releases the given capability
> + * instance @x exclusively. The capability must be held on entry.
> + */
> +# define __releases(x)         __releases_cap(x)
> +
> +/**
> + * __acquire() - function to acquire capability exclusively
> + * @x: capability instance pointer
> + *
> + * No-op function that acquires the given capability instance @x exclusively.
> + */
> +# define __acquire(x)          __acquire_cap(x)
> +
> +/**
> + * __release() - function to release capability exclusively
> + * @x: capability instance pointer
> + *
> + * No-op function that releases the given capability instance @x.
> + */
> +# define __release(x)          __release_cap(x)
> +
> +/**
> + * __cond_lock() - function that conditionally acquires a capability
> + *                 exclusively
> + * @x: capability instance pinter
> + * @c: boolean expression
> + *
> + * Return: result of @c
> + *
> + * No-op function that conditionally acquires capability instance @x
> + * exclusively, if the boolean expression @c is true. The result of @c is the
> + * return value, to be able to create a capability-enabled interface; for
> + * example:
> + *
> + * .. code-block:: c
> + *
> + *     #define spin_trylock(l) __cond_lock(&lock, _spin_trylock(&lock))
> + */
> +# define __cond_lock(x, c)     __try_acquire_cap(x, c)
> +
> +/**
> + * __must_hold_shared() - function attribute, caller must hold shared capability
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the caller must hold the given capability
> + * instance @x with shared access.
> + */
> +# define __must_hold_shared(x) __requires_shared_cap(x)
> +
> +/**
> + * __acquires_shared() - function attribute, function acquires capability shared
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function acquires the given
> + * capability instance @x with shared access, but does not release it.
> + */
> +# define __acquires_shared(x)  __acquires_shared_cap(x)
> +
> +/**
> + * __cond_acquires_shared() - function attribute, function conditionally
> + *                            acquires a capability shared
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function conditionally acquires the
> + * given capability instance @x with shared access, but does not release it.
> + */
> +# define __cond_acquires_shared(x) __try_acquires_shared_cap(1, x)
> +
> +/**
> + * __releases_shared() - function attribute, function releases a
> + *                       capability shared
> + * @x: capability instance pointer
> + *
> + * Function attribute declaring that the function releases the given capability
> + * instance @x with shared access. The capability must be held on entry.
> + */
> +# define __releases_shared(x)  __releases_shared_cap(x)
> +
> +/**
> + * __acquire_shared() - function to acquire capability shared
> + * @x: capability instance pointer
> + *
> + * No-op function that acquires the given capability instance @x with shared
> + * access.
> + */
> +# define __acquire_shared(x)   __acquire_shared_cap(x)
> +
> +/**
> + * __release_shared() - function to release capability shared
> + * @x: capability instance pointer
> + *
> + * No-op function that releases the given capability instance @x with shared
> + * access.
> + */
> +# define __release_shared(x)   __release_shared_cap(x)
> +
> +/**
> + * __cond_lock_shared() - function that conditionally acquires a capability
> + *                        shared
> + * @x: capability instance pinter
> + * @c: boolean expression
> + *
> + * Return: result of @c
> + *
> + * No-op function that conditionally acquires capability instance @x with shared
> + * access, if the boolean expression @c is true. The result of @c is the return
> + * value, to be able to create a capability-enabled interface.
> + */
> +# define __cond_lock_shared(x, c) __try_acquire_shared_cap(x, c)
>
>  #endif /* __CHECKER__ */
>
> +/**
> + * __acquire_ret() - helper to acquire capability of return value
> + * @call: call expression
> + * @ret_expr: acquire expression that uses __ret
> + */
> +#define __acquire_ret(call, ret_expr)          \
> +       ({                                      \
> +               __auto_type __ret = call;       \
> +               __acquire(ret_expr);            \
> +               __ret;                          \
> +       })
> +
> +/**
> + * __acquire_shared_ret() - helper to acquire capability shared of return value
> + * @call: call expression
> + * @ret_expr: acquire shared expression that uses __ret
> + */
> +#define __acquire_shared_ret(call, ret_expr)   \
> +       ({                                      \
> +               __auto_type __ret = call;       \
> +               __acquire_shared(ret_expr);     \
> +               __ret;                          \
> +       })
> +
> +/*
> + * Attributes to mark functions returning acquired capabilities. This is purely
> + * cosmetic to help readability, and should be used with the above macros as
> + * follows:
> + *
> + *   struct foo { spinlock_t lock; ... };
> + *   ...
> + *   #define myfunc(...) __acquire_ret(_myfunc(__VA_ARGS__), &__ret->lock)
> + *   struct foo *_myfunc(int bar) __acquires_ret;
> + *   ...
> + */
> +#define __acquires_ret         __no_capability_analysis
> +#define __acquires_shared_ret  __no_capability_analysis
> +
>  #endif /* _LINUX_COMPILER_CAPABILITY_ANALYSIS_H */
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index dc0e0c6ed075..57e09615f88d 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -613,6 +613,37 @@ config DEBUG_FORCE_WEAK_PER_CPU
>           To ensure that generic code follows the above rules, this
>           option forces all percpu variables to be defined as weak.
>
> +config WARN_CAPABILITY_ANALYSIS
> +       bool "Compiler capability-analysis warnings"
> +       depends on CC_IS_CLANG && CLANG_VERSION >= 220000
> +       # Branch profiling re-defines "if", which messes with the compiler's
> +       # ability to analyze __cond_acquires(..), resulting in false positives.
> +       depends on !TRACE_BRANCH_PROFILING

Err, wow! What and huh, and why? Crikes. I'm amazed you found such an
option exists. I must be very naive to have never heard of it and now
I wonder if it is needed and load bearing?

Ian


> +       default y
> +       help
> +         Capability analysis is a C language extension, which enables
> +         statically checking that user-definable "capabilities" are acquired
> +         and released where required.
> +
> +         Clang's name of the feature ("Thread Safety Analysis") refers to
> +         the original name of the feature; it was later expanded to be a
> +         generic "Capability Analysis" framework.
> +
> +         Requires Clang 22 or later.
> +
> +         Produces warnings by default. Select CONFIG_WERROR if you wish to
> +         turn these warnings into errors.
> +
> +config WARN_CAPABILITY_ANALYSIS_ALL
> +       bool "Enable capability analysis for all source files"
> +       depends on WARN_CAPABILITY_ANALYSIS
> +       depends on EXPERT && !COMPILE_TEST
> +       help
> +         Enable tree-wide capability analysis. This is likely to produce a
> +         large number of false positives - enable at your own risk.
> +
> +         If unsure, say N.
> +
>  endmenu # "Compiler options"
>
>  menu "Generic Kernel Debugging Instruments"
> diff --git a/scripts/Makefile.capability-analysis b/scripts/Makefile.capability-analysis
> new file mode 100644
> index 000000000000..e137751a4c9a
> --- /dev/null
> +++ b/scripts/Makefile.capability-analysis
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +capability-analysis-cflags := -DWARN_CAPABILITY_ANALYSIS       \
> +       -fexperimental-late-parse-attributes -Wthread-safety    \
> +       -Wthread-safety-pointer -Wthread-safety-beta
> +
> +export CFLAGS_CAPABILITY_ANALYSIS := $(capability-analysis-cflags)
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 1d581ba5df66..e0ac273bf9eb 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -105,6 +105,16 @@ _c_flags += $(if $(patsubst n%,, \
>         -D__KCSAN_INSTRUMENT_BARRIERS__)
>  endif
>
> +#
> +# Enable capability analysis flags only where explicitly opted in.
> +# (depends on variables CAPABILITY_ANALYSIS_obj.o, CAPABILITY_ANALYSIS)
> +#
> +ifeq ($(CONFIG_WARN_CAPABILITY_ANALYSIS),y)
> +_c_flags += $(if $(patsubst n%,, \
> +               $(CAPABILITY_ANALYSIS_$(target-stem).o)$(CAPABILITY_ANALYSIS)$(if $(is-kernel-object),$(CONFIG_WARN_CAPABILITY_ANALYSIS_ALL))), \
> +               $(CFLAGS_CAPABILITY_ANALYSIS))
> +endif
> +
>  #
>  # Enable AutoFDO build flags except some files or directories we don't want to
>  # enable (depends on variables AUTOFDO_PROFILE_obj.o and AUTOFDO_PROFILE).
> --
> 2.51.0.384.g4c02a37b29-goog
>


  reply	other threads:[~2025-09-18 15:58 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-18 13:59 [PATCH v3 00/35] Compiler-Based Capability- and Locking-Analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 01/35] compiler_types: Move lock checking attributes to compiler-capability-analysis.h Marco Elver
2025-09-18 13:59 ` [PATCH v3 02/35] compiler-capability-analysis: Add infrastructure for Clang's capability analysis Marco Elver
2025-09-18 15:58   ` Ian Rogers [this message]
2025-09-18 16:03     ` Bart Van Assche
2025-09-18 16:14       ` Steven Rostedt
2025-09-18 13:59 ` [PATCH v3 03/35] compiler-capability-analysis: Add test stub Marco Elver
2025-09-18 13:59 ` [PATCH v3 04/35] Documentation: Add documentation for Compiler-Based Capability Analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 05/35] checkpatch: Warn about capability_unsafe() without comment Marco Elver
2025-09-18 20:36   ` Joe Perches
2025-09-18 13:59 ` [PATCH v3 06/35] cleanup: Basic compatibility with capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 07/35] lockdep: Annotate lockdep assertions for " Marco Elver
2025-09-18 13:59 ` [PATCH v3 08/35] locking/rwlock, spinlock: Support Clang's " Marco Elver
2025-09-18 13:59 ` [PATCH v3 09/35] compiler-capability-analysis: Change __cond_acquires to take return value Marco Elver
2025-09-18 13:59 ` [PATCH v3 10/35] locking/mutex: Support Clang's capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 11/35] locking/seqlock: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 12/35] bit_spinlock: Include missing <asm/processor.h> Marco Elver
2025-09-18 13:59 ` [PATCH v3 13/35] bit_spinlock: Support Clang's capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 14/35] rcu: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 15/35] srcu: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 16/35] kref: Add capability-analysis annotations Marco Elver
2025-09-18 13:59 ` [PATCH v3 17/35] locking/rwsem: Support Clang's capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 18/35] locking/local_lock: Include missing headers Marco Elver
2025-09-18 13:59 ` [PATCH v3 19/35] locking/local_lock: Support Clang's capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 20/35] locking/ww_mutex: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 21/35] debugfs: Make debugfs_cancellation a capability struct Marco Elver
2025-09-18 13:59 ` [PATCH v3 22/35] compiler-capability-analysis: Remove Sparse support Marco Elver
2025-09-18 13:59 ` [PATCH v3 23/35] compiler-capability-analysis: Remove __cond_lock() function-like helper Marco Elver
2025-09-18 13:59 ` [PATCH v3 24/35] compiler-capability-analysis: Introduce header suppressions Marco Elver
2025-09-18 13:59 ` [PATCH v3 25/35] compiler: Let data_race() imply disabled capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 26/35] MAINTAINERS: Add entry for Capability Analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 27/35] kfence: Enable capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 28/35] kcov: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 29/35] kcsan: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 30/35] stackdepot: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 31/35] rhashtable: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 32/35] printk: Move locking annotation to printk.c Marco Elver
2025-09-18 13:59 ` [PATCH v3 33/35] security/tomoyo: Enable capability analysis Marco Elver
2025-09-18 13:59 ` [PATCH v3 34/35] crypto: " Marco Elver
2025-09-18 13:59 ` [PATCH v3 35/35] sched: Enable capability analysis for core.c and fair.c Marco Elver
2025-09-18 14:15 ` [PATCH v3 00/35] Compiler-Based Capability- and Locking-Analysis Christoph Hellwig
2025-09-18 14:30   ` Marco Elver
2025-09-18 14:38     ` Christoph Hellwig
2025-09-18 17:45   ` Nathan Chancellor
2025-09-18 19:40     ` Nathan Chancellor
2025-09-19 14:08     ` Christoph Hellwig
2025-09-19 14:09       ` Christoph Hellwig
2025-09-22  9:33         ` Marco Elver
2025-09-22 17:11           ` Christoph Hellwig
2025-09-23 19:49           ` Nathan Chancellor
2025-09-19 17:20       ` Bart Van Assche
2025-09-22 17:12         ` Christoph Hellwig
2025-09-20 10:23       ` Marco Elver
2025-09-20 12:44         ` Marco Elver
2025-09-18 15:49 ` Linus Torvalds
2025-09-18 21:26   ` Marco Elver
2025-09-18 21:47     ` Linus Torvalds
2025-09-19  9:10       ` Marco Elver
2025-11-13 14:30         ` Marco Elver
2025-11-14  4:38           ` Nathan Chancellor
2025-11-14 13:22             ` Marco Elver
2025-09-18 16:21 ` Ian Rogers
2025-09-18 19:41 ` [syzbot ci] " syzbot ci
2025-09-19  7:05   ` Marco Elver

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAP-5=fUfbMAKrLC_z04o9r0kGZ02tpHfv8cOecQAQaYPx44awA@mail.gmail.com' \
    --to=irogers@google.com \
    --cc=arnd@arndb.de \
    --cc=boqun.feng@gmail.com \
    --cc=bvanassche@acm.org \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=dvyukov@google.com \
    --cc=edumazet@google.com \
    --cc=elver@google.com \
    --cc=frederic@kernel.org \
    --cc=glider@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hch@lst.de \
    --cc=herbert@gondor.apana.org.au \
    --cc=jannh@google.com \
    --cc=joelagnelf@nvidia.com \
    --cc=josh@joshtriplett.org \
    --cc=justinstitt@google.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=kees@kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=linux-sparse@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=longman@redhat.com \
    --cc=luc.vanoostenryck@gmail.com \
    --cc=lukas.bulwahn@gmail.com \
    --cc=mark.rutland@arm.com \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mingo@kernel.org \
    --cc=morbo@google.com \
    --cc=nathan@kernel.org \
    --cc=neeraj.upadhyay@kernel.org \
    --cc=nick.desaulniers+lkml@gmail.com \
    --cc=ojeda@kernel.org \
    --cc=paulmck@kernel.org \
    --cc=penguin-kernel@i-love.sakura.ne.jp \
    --cc=peterz@infradead.org \
    --cc=rcu@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=takedakn@nttdata.co.jp \
    --cc=tglx@linutronix.de \
    --cc=tgraf@suug.ch \
    --cc=urezki@gmail.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox