]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KUnit: ffs: Validate all the __attribute_const__ annotations
authorKees Cook <kees@kernel.org>
Mon, 4 Aug 2025 16:44:13 +0000 (09:44 -0700)
committerKees Cook <kees@kernel.org>
Mon, 8 Sep 2025 21:58:52 +0000 (14:58 -0700)
While tracking down a problem where constant expressions used by
BUILD_BUG_ON() suddenly stopped working[1], we found that an added static
initializer was convincing the compiler that it couldn't track the state
of the prior statically initialized value. Tracing this down found that
ffs() was used in the initializer macro, but since it wasn't marked with
__attribute_const__, the compiler had to assume the function might
change variable states as a side-effect (which is not true for ffs(),
which provides deterministic math results).

Validate all the __attibute_const__ annotations were found for all
architectures by reproducing the specific problem encountered in the
original bug report.

Build and run tested with everything I could reach with KUnit:

$ ./tools/testing/kunit/kunit.py run --arch=x86_64 ffs
$ ./tools/testing/kunit/kunit.py run --arch=i386 ffs
$ ./tools/testing/kunit/kunit.py run --arch=arm64 --make_options "CROSS_COMPILE=aarch64-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=arm --make_options "CROSS_COMPILE=arm-linux-gnueabi-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=powerpc ffs
$ ./tools/testing/kunit/kunit.py run --arch=powerpc32 ffs
$ ./tools/testing/kunit/kunit.py run --arch=powerpcle ffs
$ ./tools/testing/kunit/kunit.py run --arch=m68k ffs
$ ./tools/testing/kunit/kunit.py run --arch=loongarch ffs
$ ./tools/testing/kunit/kunit.py run --arch=s390 --make_options "CROSS_COMPILE=s390x-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=riscv --make_options "CROSS_COMPILE=riscv64-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=riscv32 --make_options "CROSS_COMPILE=riscv64-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=sparc --make_options "CROSS_COMPILE=sparc64-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=sparc64 --make_options "CROSS_COMPILE=sparc64-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=alpha --make_options "CROSS_COMPILE=alpha-linux-gnu-" ffs
$ ./tools/testing/kunit/kunit.py run --arch=sh --make_options "CROSS_COMPILE=sh4-linux-gnu-" ffs

Closes: https://github.com/KSPP/linux/issues/364
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250804164417.1612371-17-kees@kernel.org
Signed-off-by: Kees Cook <kees@kernel.org>
lib/tests/ffs_kunit.c

index ed11456b116e46a7d411b224a7aad1cb8125aaa2..9a329cdc09c247532baeeedc4664151f96526feb 100644 (file)
@@ -496,6 +496,46 @@ static void ffz_edge_cases_test(struct kunit *test)
        }
 }
 
+/*
+ * To have useful build error output, split the tests into separate
+ * functions so it's clear which are missing __attribute_const__.
+ */
+#define CREATE_WRAPPER(func)                                           \
+static noinline bool build_test_##func(void)                           \
+{                                                                      \
+       int init_##func = 32;                                           \
+       int result_##func = func(6);                                    \
+                                                                       \
+       /* Does the static initializer vanish after calling func? */    \
+       BUILD_BUG_ON(init_##func < 32);                                 \
+                                                                       \
+       /* "Consume" the results so optimizer doesn't drop them. */     \
+       barrier_data(&init_##func);                                     \
+       barrier_data(&result_##func);                                   \
+                                                                       \
+       return true;                                                    \
+}
+CREATE_WRAPPER(ffs)
+CREATE_WRAPPER(fls)
+CREATE_WRAPPER(__ffs)
+CREATE_WRAPPER(__fls)
+CREATE_WRAPPER(ffz)
+#undef CREATE_WRAPPER
+
+/*
+ * Make sure that __attribute_const__ has be applied to all the
+ * functions. This is a regression test for:
+ * https://github.com/KSPP/linux/issues/364
+ */
+static void ffs_attribute_const_test(struct kunit *test)
+{
+       KUNIT_EXPECT_TRUE(test, build_test_ffs());
+       KUNIT_EXPECT_TRUE(test, build_test_fls());
+       KUNIT_EXPECT_TRUE(test, build_test___ffs());
+       KUNIT_EXPECT_TRUE(test, build_test___fls());
+       KUNIT_EXPECT_TRUE(test, build_test_ffz());
+}
+
 /*
  * KUnit test case definitions
  */