| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * Macros and attributes for compiler-based static context analysis. | |
| */ | |
| #ifndef _LINUX_COMPILER_CONTEXT_ANALYSIS_H | |
| #define _LINUX_COMPILER_CONTEXT_ANALYSIS_H | |
| #if defined(WARN_CONTEXT_ANALYSIS) && !defined(__CHECKER__) && !defined(__GENKSYMS__) | |
| /* | |
| * These attributes define new context lock (Clang: capability) types. | |
| * Internal only. | |
| */ | |
| # define __ctx_lock_type(name) __attribute__((capability(#name))) | |
| # define __reentrant_ctx_lock __attribute__((reentrant_capability)) | |
| # define __acquires_ctx_lock(...) __attribute__((acquire_capability(__VA_ARGS__))) | |
| # define __acquires_shared_ctx_lock(...) __attribute__((acquire_shared_capability(__VA_ARGS__))) | |
| # define __try_acquires_ctx_lock(ret, var) __attribute__((try_acquire_capability(ret, var))) | |
| # define __try_acquires_shared_ctx_lock(ret, var) __attribute__((try_acquire_shared_capability(ret, var))) | |
| # define __releases_ctx_lock(...) __attribute__((release_capability(__VA_ARGS__))) | |
| # define __releases_shared_ctx_lock(...) __attribute__((release_shared_capability(__VA_ARGS__))) | |
| # define __returns_ctx_lock(var) __attribute__((lock_returned(var))) | |
| /* | |
| * The below are used to annotate code being checked. Internal only. | |
| */ | |
| # define __excludes_ctx_lock(...) __attribute__((locks_excluded(__VA_ARGS__))) | |
| # define __requires_ctx_lock(...) __attribute__((requires_capability(__VA_ARGS__))) | |
| # define __requires_shared_ctx_lock(...) __attribute__((requires_shared_capability(__VA_ARGS__))) | |
| /* | |
| * The "assert_capability" attribute is a bit confusingly named. It does not | |
| * generate a check. Instead, it tells the analysis to *assume* the capability | |
| * is held. This is used for augmenting runtime assertions, that can then help | |
| * with patterns beyond the compiler's static reasoning abilities. | |
| */ | |
| # define __assumes_ctx_lock(...) __attribute__((assert_capability(__VA_ARGS__))) | |
| # define __assumes_shared_ctx_lock(...) __attribute__((assert_shared_capability(__VA_ARGS__))) | |
| /** | |
| * __guarded_by() - struct member and globals attribute, declares variable | |
| * only accessible within active context | |
| * @...: context lock instance pointer(s) | |
| * | |
| * Declares that the struct member or global variable is only accessible within | |
| * the context entered by the given context lock(s). Read operations on the data | |
| * require shared access to at least one of the context locks, while write | |
| * operations require exclusive access to all listed context locks. | |
| * | |
| * .. code-block:: c | |
| * | |
| * struct some_state { | |
| * spinlock_t lock; | |
| * long counter __guarded_by(&lock); | |
| * }; | |
| * | |
| * struct some_state { | |
| * spinlock_t lock1, lock2; | |
| * long counter __guarded_by(&lock1, &lock2); | |
| * }; | |
| */ | |
| # define __guarded_by(...) __attribute__((guarded_by(__VA_ARGS__))) | |
| /** | |
| * __pt_guarded_by() - struct member and globals attribute, declares pointed-to | |
| * data only accessible within active context | |
| * @...: context lock instance pointer(s) | |
| * | |
| * Declares that the data pointed to by the struct member pointer or global | |
| * pointer is only accessible within the context entered by the given context | |
| * lock(s). Read operations on the data require shared access to at least one | |
| * of the context locks, while write operations require exclusive access to all | |
| * listed context locks. | |
| * | |
| * .. code-block:: c | |
| * | |
| * struct some_state { | |
| * spinlock_t lock; | |
| * long *counter __pt_guarded_by(&lock); | |
| * }; | |
| * | |
| * struct some_state { | |
| * spinlock_t lock1, lock2; | |
| * long *counter __pt_guarded_by(&lock1, &lock2); | |
| * }; | |
| */ | |
| # define __pt_guarded_by(...) __attribute__((pt_guarded_by(__VA_ARGS__))) | |
| /** | |
| * context_lock_struct() - declare or define a context lock struct | |
| * @name: struct name | |
| * | |
| * Helper to declare or define a struct type that is also a context lock. | |
| * | |
| * .. code-block:: c | |
| * | |
| * context_lock_struct(my_handle) { | |
| * int foo; | |
| * long bar; | |
| * }; | |
| * | |
| * struct some_state { | |
| * ... | |
| * }; | |
| * // ... declared elsewhere ... | |
| * context_lock_struct(some_state); | |
| * | |
| * Note: The implementation defines several helper functions that can acquire | |
| * and release the context lock. | |
| */ | |
| # define context_lock_struct(name, ...) \ | |
| struct __ctx_lock_type(name) __VA_ARGS__ name; \ | |
| static __always_inline void __acquire_ctx_lock(const struct name *var) \ | |
| __attribute__((overloadable)) __no_context_analysis __acquires_ctx_lock(var) { } \ | |
| static __always_inline void __acquire_shared_ctx_lock(const struct name *var) \ | |
| __attribute__((overloadable)) __no_context_analysis __acquires_shared_ctx_lock(var) { } \ | |
| static __always_inline bool __try_acquire_ctx_lock(const struct name *var, bool ret) \ | |
| __attribute__((overloadable)) __no_context_analysis __try_acquires_ctx_lock(1, var) \ | |
| { return ret; } \ | |
| static __always_inline bool __try_acquire_shared_ctx_lock(const struct name *var, bool ret) \ | |
| __attribute__((overloadable)) __no_context_analysis __try_acquires_shared_ctx_lock(1, var) \ | |
| { return ret; } \ | |
| static __always_inline void __release_ctx_lock(const struct name *var) \ | |
| __attribute__((overloadable)) __no_context_analysis __releases_ctx_lock(var) { } \ | |
| static __always_inline void __release_shared_ctx_lock(const struct name *var) \ | |
| __attribute__((overloadable)) __no_context_analysis __releases_shared_ctx_lock(var) { } \ | |
| static __always_inline void __assume_ctx_lock(const struct name *var) \ | |
| __attribute__((overloadable)) __assumes_ctx_lock(var) { } \ | |
| static __always_inline void __assume_shared_ctx_lock(const struct name *var) \ | |
| __attribute__((overloadable)) __assumes_shared_ctx_lock(var) { } \ | |
| struct name | |
| /** | |
| * disable_context_analysis() - disables context analysis | |
| * | |
| * Disables context analysis. Must be paired with a later | |
| * enable_context_analysis(). | |
| */ | |
| # define disable_context_analysis() \ | |
| __diag_push(); \ | |
| __diag_ignore_all("-Wunknown-warning-option", "") \ | |
| __diag_ignore_all("-Wthread-safety", "") \ | |
| __diag_ignore_all("-Wthread-safety-pointer", "") | |
| /** | |
| * enable_context_analysis() - re-enables context analysis | |
| * | |
| * Re-enables context analysis. Must be paired with a prior | |
| * disable_context_analysis(). | |
| */ | |
| # define enable_context_analysis() __diag_pop() | |
| /** | |
| * __no_context_analysis - function attribute, disables context analysis | |
| * | |
| * Function attribute denoting that context analysis is disabled for the | |
| * whole function. Prefer use of `context_unsafe()` where possible. | |
| */ | |
| # define __no_context_analysis __attribute__((no_thread_safety_analysis)) | |
| #else /* !WARN_CONTEXT_ANALYSIS */ | |
| # define __ctx_lock_type(name) | |
| # define __reentrant_ctx_lock | |
| # define __acquires_ctx_lock(...) | |
| # define __acquires_shared_ctx_lock(...) | |
| # define __try_acquires_ctx_lock(ret, var) | |
| # define __try_acquires_shared_ctx_lock(ret, var) | |
| # define __releases_ctx_lock(...) | |
| # define __releases_shared_ctx_lock(...) | |
| # define __assumes_ctx_lock(...) | |
| # define __assumes_shared_ctx_lock(...) | |
| # define __returns_ctx_lock(var) | |
| # define __guarded_by(...) | |
| # define __pt_guarded_by(...) | |
| # define __excludes_ctx_lock(...) | |
| # define __requires_ctx_lock(...) | |
| # define __requires_shared_ctx_lock(...) | |
| # define __acquire_ctx_lock(var) do { } while (0) | |
| # define __acquire_shared_ctx_lock(var) do { } while (0) | |
| # define __try_acquire_ctx_lock(var, ret) (ret) | |
| # define __try_acquire_shared_ctx_lock(var, ret) (ret) | |
| # define __release_ctx_lock(var) do { } while (0) | |
| # define __release_shared_ctx_lock(var) do { } while (0) | |
| # define __assume_ctx_lock(var) do { (void)(var); } while (0) | |
| # define __assume_shared_ctx_lock(var) do { (void)(var); } while (0) | |
| # define context_lock_struct(name, ...) struct __VA_ARGS__ name | |
| # define disable_context_analysis() | |
| # define enable_context_analysis() | |
| # define __no_context_analysis | |
| #endif /* WARN_CONTEXT_ANALYSIS */ | |
| /** | |
| * context_unsafe() - disable context checking for contained code | |
| * | |
| * Disables context 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 context_unsafe(d->counter); | |
| * } | |
| */ | |
| #define context_unsafe(...) \ | |
| ({ \ | |
| disable_context_analysis(); \ | |
| __VA_ARGS__; \ | |
| enable_context_analysis() \ | |
| }) | |
| /** | |
| * __context_unsafe() - function attribute, disable context checking | |
| * @comment: comment explaining why opt-out is safe | |
| * | |
| * Function attribute denoting that context analysis is disabled for the | |
| * whole function. Forces adding an inline comment as argument. | |
| */ | |
| #define __context_unsafe(comment) __no_context_analysis | |
| /** | |
| * context_unsafe_alias() - helper to insert a context lock "alias barrier" | |
| * @p: pointer aliasing a context lock or object containing context locks | |
| * | |
| * No-op function that acts as a "context lock 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 context_unsafe_alias(p) _context_unsafe_alias((void **)&(p)) | |
| static inline void _context_unsafe_alias(void **p) { } | |
| /** | |
| * token_context_lock() - declare an abstract global context lock instance | |
| * @name: token context lock name | |
| * | |
| * Helper that declares an abstract global context lock instance @name, but not | |
| * backed by a real data structure (linker error if accidentally referenced). | |
| * The type name is `__ctx_lock_@name`. | |
| */ | |
| #define token_context_lock(name, ...) \ | |
| context_lock_struct(__ctx_lock_##name, ##__VA_ARGS__) {}; \ | |
| extern const struct __ctx_lock_##name *name | |
| /** | |
| * token_context_lock_instance() - declare another instance of a global context lock | |
| * @ctx: token context lock previously declared with token_context_lock() | |
| * @name: name of additional global context lock instance | |
| * | |
| * Helper that declares an additional instance @name of the same token context | |
| * lock class @ctx. This is helpful where multiple related token contexts are | |
| * declared, to allow using the same underlying type (`__ctx_lock_@ctx`) as | |
| * function arguments. | |
| */ | |
| #define token_context_lock_instance(ctx, name) \ | |
| extern const struct __ctx_lock_##ctx *name | |
| /* | |
| * Common keywords for static context analysis. | |
| */ | |
| /** | |
| * __must_hold() - function attribute, caller must hold exclusive context lock | |
| * | |
| * Function attribute declaring that the caller must hold the given context | |
| * lock instance(s) exclusively. | |
| */ | |
| #define __must_hold(...) __requires_ctx_lock(__VA_ARGS__) | |
| /** | |
| * __must_not_hold() - function attribute, caller must not hold context lock | |
| * | |
| * Function attribute declaring that the caller must not hold the given context | |
| * lock instance(s). | |
| */ | |
| #define __must_not_hold(...) __excludes_ctx_lock(__VA_ARGS__) | |
| /** | |
| * __acquires() - function attribute, function acquires context lock exclusively | |
| * | |
| * Function attribute declaring that the function acquires the given context | |
| * lock instance(s) exclusively, but does not release them. | |
| */ | |
| #define __acquires(...) __acquires_ctx_lock(__VA_ARGS__) | |
| /* | |
| * Clang's analysis does not care precisely about the value, only that it is | |
| * either zero or non-zero. So the __cond_acquires() interface might be | |
| * misleading if we say that @ret is the value returned if acquired. Instead, | |
| * provide symbolic variants which we translate. | |
| */ | |
| #define __cond_acquires_impl_true(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(1, x) | |
| #define __cond_acquires_impl_false(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(0, x) | |
| #define __cond_acquires_impl_nonzero(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(1, x) | |
| #define __cond_acquires_impl_0(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(0, x) | |
| #define __cond_acquires_impl_nonnull(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(1, x) | |
| #define __cond_acquires_impl_NULL(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(0, x) | |
| /** | |
| * __cond_acquires() - function attribute, function conditionally | |
| * acquires a context lock exclusively | |
| * @ret: abstract value returned by function if context lock acquired | |
| * @x: context lock instance pointer | |
| * | |
| * Function attribute declaring that the function conditionally acquires the | |
| * given context lock instance @x exclusively, but does not release it. The | |
| * function return value @ret denotes when the context lock is acquired. | |
| * | |
| * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. | |
| */ | |
| #define __cond_acquires(ret, x) __cond_acquires_impl_##ret(x) | |
| /** | |
| * __releases() - function attribute, function releases a context lock exclusively | |
| * | |
| * Function attribute declaring that the function releases the given context | |
| * lock instance(s) exclusively. The associated context(s) must be active on | |
| * entry. | |
| */ | |
| #define __releases(...) __releases_ctx_lock(__VA_ARGS__) | |
| /* | |
| * Clang's analysis does not care precisely about the value, only that it is | |
| * either zero or non-zero. So the __cond_acquires() interface might be | |
| * misleading if we say that @ret is the value returned if acquired. Instead, | |
| * provide symbolic variants which we translate. | |
| */ | |
| #define __cond_acquires_impl_not_true(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(0, x) | |
| #define __cond_acquires_impl_not_false(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(1, x) | |
| #define __cond_acquires_impl_not_nonzero(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(0, x) | |
| #define __cond_acquires_impl_not_0(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(1, x) | |
| #define __cond_acquires_impl_not_nonnull(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(0, x) | |
| #define __cond_acquires_impl_not_NULL(x, ...) __try_acquires##__VA_ARGS__##_ctx_lock(1, x) | |
| /** | |
| * __cond_releases() - function attribute, function conditionally | |
| * releases a context lock exclusively | |
| * @ret: abstract value returned by function if context lock releases | |
| * @x: context lock instance pointer | |
| * | |
| * Function attribute declaring that the function conditionally releases the | |
| * given context lock instance @x exclusively. The associated context(s) must | |
| * be active on entry. The function return value @ret denotes when the context | |
| * lock is released. | |
| * | |
| * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. | |
| * | |
| * NOTE: clang does not have a native attribute for this; instead implement | |
| * it as an unconditional release and a conditional acquire for the | |
| * inverted condition -- which is semantically equivalent. | |
| */ | |
| #define __cond_releases(ret, x) __releases(x) __cond_acquires_impl_not_##ret(x) | |
| /** | |
| * __acquire() - function to acquire context lock exclusively | |
| * @x: context lock instance pointer | |
| * | |
| * No-op function that acquires the given context lock instance @x exclusively. | |
| */ | |
| #define __acquire(x) __acquire_ctx_lock(x) | |
| /** | |
| * __release() - function to release context lock exclusively | |
| * @x: context lock instance pointer | |
| * | |
| * No-op function that releases the given context lock instance @x. | |
| */ | |
| #define __release(x) __release_ctx_lock(x) | |
| /** | |
| * __must_hold_shared() - function attribute, caller must hold shared context lock | |
| * | |
| * Function attribute declaring that the caller must hold the given context | |
| * lock instance(s) with shared access. | |
| */ | |
| #define __must_hold_shared(...) __requires_shared_ctx_lock(__VA_ARGS__) | |
| /** | |
| * __acquires_shared() - function attribute, function acquires context lock shared | |
| * | |
| * Function attribute declaring that the function acquires the given | |
| * context lock instance(s) with shared access, but does not release them. | |
| */ | |
| #define __acquires_shared(...) __acquires_shared_ctx_lock(__VA_ARGS__) | |
| /** | |
| * __cond_acquires_shared() - function attribute, function conditionally | |
| * acquires a context lock shared | |
| * @ret: abstract value returned by function if context lock acquired | |
| * @x: context lock instance pointer | |
| * | |
| * Function attribute declaring that the function conditionally acquires the | |
| * given context lock instance @x with shared access, but does not release it. | |
| * The function return value @ret denotes when the context lock is acquired. | |
| * | |
| * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. | |
| */ | |
| #define __cond_acquires_shared(ret, x) __cond_acquires_impl_##ret(x, _shared) | |
| /** | |
| * __releases_shared() - function attribute, function releases a | |
| * context lock shared | |
| * | |
| * Function attribute declaring that the function releases the given context | |
| * lock instance(s) with shared access. The associated context(s) must be | |
| * active on entry. | |
| */ | |
| #define __releases_shared(...) __releases_shared_ctx_lock(__VA_ARGS__) | |
| /** | |
| * __acquire_shared() - function to acquire context lock shared | |
| * @x: context lock instance pointer | |
| * | |
| * No-op function that acquires the given context lock instance @x with shared | |
| * access. | |
| */ | |
| #define __acquire_shared(x) __acquire_shared_ctx_lock(x) | |
| /** | |
| * __release_shared() - function to release context lock shared | |
| * @x: context lock instance pointer | |
| * | |
| * No-op function that releases the given context lock instance @x with shared | |
| * access. | |
| */ | |
| #define __release_shared(x) __release_shared_ctx_lock(x) | |
| /** | |
| * __acquire_ret() - helper to acquire context lock 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 context lock 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 context locks. | |
| * | |
| * 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_context_analysis | |
| #define __acquires_shared_ret __no_context_analysis | |
| #endif /* _LINUX_COMPILER_CONTEXT_ANALYSIS_H */ |