aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2022-04-26 16:31:09 +0100
committerDaniel Thompson <daniel.thompson@linaro.org>2022-04-27 11:49:30 +0100
commitda75c73e41fc4501a23d34ac88984389eb73dd25 (patch)
tree14444c1ccb1930a93f057bd1ef24d32e587a58e4
parent54ea8a7c9b6da22299c93c15cfa385ecba84cb29 (diff)
[RFC] compiler.h: Introduce the ASSUME() macro
Static analyzers, by their nature, inspect functions and "like" to consider what happens when arguments do not meet the authors intent. For example they may assume that a list is empty (or an array has zero-elements) even when that is impossible in practice. The ASSUME() macro allows us to teach static analyzers that certain conditions are impossible. In some ways ASSUME() is similar to userspace macros such as assert() in that the condition must always be true. The reason this macro adopts a different name is that's primary intent is to teach a static analyzer about the code invariants. Sure, it could be converted into a runtime check but it should only be added where the author "knows" it will not trigger. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
-rw-r--r--include/linux/compiler.h25
1 files changed, 25 insertions, 0 deletions
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 4e7b4861d234..27ca0e0047ff 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -221,6 +221,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
#endif
#ifdef __clang_analyzer__
+
/*
* Provide a way for macros to optimize themselves for static analyzers.
* Currently this is limited to clang-analyzer since that's what we have
@@ -230,8 +231,32 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
* same machinery we use to handle config options in C expressions.
*/
#define CC_IS_STATIC_ANALYZER 1
+
+/*
+ * assume_not_reached() has no effect on code-generation. It simply prevents
+ * static analyzers from following branches it is called from. This can be
+ * used to help the analyzer track "impossible" states by reasoning about the
+ * conditions passed to macros such as ASSUME() and WARN_ON().
+ */
+static inline void assume_not_reached(void) __attribute__((analyzer_noreturn)) {}
+#else /* __clang_analyzer__ */
+static inline void assume_not_reached(void) {}
#endif /* __clang_analyzer__ */
+/*
+ * ASSUME() allows us to direct a static analyzer to assume that x is true.
+ *
+ * Providing the optimizer can prove the evaluating x has no side-effects then
+ * ASSUME() should not affect code generation. The most common use of ASSUME()
+ * is (or should be) to specify the bounds of a variable using an inequality.
+ * Such cases can be trivially handled by the optimizer.
+ */
+#define ASSUME(x) \
+ do { \
+ if (!(x)) \
+ assume_not_reached(); \
+ } while (0)
+
#endif /* __KERNEL__ */
/*