The only test that uses the FD_* macros passes fd 1, so nothing noticed that they used the wrong bits for fds 31-63 of each word on 64-bit architectures.
Check that FD_SET() and FD_CLR() change exactly one fd, for every fd below FD_SETSIZE. Assisted-by: LLM Signed-off-by: Danish Khateeb <[email protected]> --- Notes: v2: - Dropped the select() test. - Moved the FD_* test to the stdlib tests, with its helper in the same order as the test cases. - Shortened it: FD_CLR() is now checked on a set filled with memset(). v1: https://lore.kernel.org/all/[email protected]/ Tested with nolibc-test on x86_64 (GCC and clang), i386, arm, arm64 and sparc64 (qemu-user), and against glibc. With the fix, fd_set passes everywhere. Without it, fd_set fails on the 64-bit architectures (or UBSan traps on the shift) and passes on the 32-bit ones, which were not affected. tools/testing/selftests/nolibc/nolibc-test.c | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 37c11a7fce23..1995d67dcca6 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1841,6 +1841,26 @@ int test_time_types(void) return 0; } +int test_fd_set(void) +{ + fd_set set, clr; + int fd, i; + + /* FD_SET() and FD_CLR() must change exactly one fd */ + for (fd = 0; fd < FD_SETSIZE; fd++) { + FD_ZERO(&set); + FD_SET(fd, &set); + memset(&clr, 0xff, sizeof(clr)); + FD_CLR(fd, &clr); + for (i = 0; i < FD_SETSIZE; i++) + if (!!FD_ISSET(i, &set) != (i == fd) || + !!FD_ISSET(i, &clr) != (i != fd)) + return 1; + } + + return 0; +} + int test_malloc(void) { size_t sz_array1, sz_array2, sz_array3; @@ -2022,6 +2042,7 @@ int run_stdlib(int min, int max) CASE_TEST(memchr_foobar6_o); EXPECT_STREQ(1, memchr("foobar", 'o', 6), "oobar"); break; CASE_TEST(memchr_foobar3_b); EXPECT_STRZR(1, memchr("foobar", 'b', 3)); break; CASE_TEST(time_types); EXPECT_ZR(is_nolibc, test_time_types()); break; + CASE_TEST(fd_set); EXPECT_ZR(1, test_fd_set()); break; CASE_TEST(makedev); EXPECT_EQ(1, makedev(0x12, 0x34), 0x1234); break; CASE_TEST(major); EXPECT_EQ(1, major(0x1234), 0x12); break; CASE_TEST(minor); EXPECT_EQ(1, minor(0x1234), 0x34); break; -- 2.55.0

