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


Reply via email to