Skip to content

Commit 95719df

Browse files
committed
KUnit: ffs: Validate all the __attribute_const__ annotations
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: KSPP#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>
1 parent 07008b9 commit 95719df

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

lib/tests/ffs_kunit.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,46 @@ static void ffz_edge_cases_test(struct kunit *test)
496496
}
497497
}
498498

499+
/*
500+
* To have useful build error output, split the tests into separate
501+
* functions so it's clear which are missing __attribute_const__.
502+
*/
503+
#define CREATE_WRAPPER(func) \
504+
static noinline bool build_test_##func(void) \
505+
{ \
506+
int init_##func = 32; \
507+
int result_##func = func(6); \
508+
\
509+
/* Does the static initializer vanish after calling func? */ \
510+
BUILD_BUG_ON(init_##func < 32); \
511+
\
512+
/* "Consume" the results so optimizer doesn't drop them. */ \
513+
barrier_data(&init_##func); \
514+
barrier_data(&result_##func); \
515+
\
516+
return true; \
517+
}
518+
CREATE_WRAPPER(ffs)
519+
CREATE_WRAPPER(fls)
520+
CREATE_WRAPPER(__ffs)
521+
CREATE_WRAPPER(__fls)
522+
CREATE_WRAPPER(ffz)
523+
#undef CREATE_WRAPPER
524+
525+
/*
526+
* Make sure that __attribute_const__ has be applied to all the
527+
* functions. This is a regression test for:
528+
* https://github.com/KSPP/linux/issues/364
529+
*/
530+
static void ffs_attribute_const_test(struct kunit *test)
531+
{
532+
KUNIT_EXPECT_TRUE(test, build_test_ffs());
533+
KUNIT_EXPECT_TRUE(test, build_test_fls());
534+
KUNIT_EXPECT_TRUE(test, build_test___ffs());
535+
KUNIT_EXPECT_TRUE(test, build_test___fls());
536+
KUNIT_EXPECT_TRUE(test, build_test_ffz());
537+
}
538+
499539
/*
500540
* KUnit test case definitions
501541
*/

0 commit comments

Comments
 (0)