root/include/linux/compiler-context-analysis.h
/* 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
 *
 * Declares that the struct member or global variable is only accessible within
 * the context entered by the given context lock. 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 only accessible within active context
 *
 * 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. 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__)))

/**
 * 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__)

/**
 * __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 */