gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/select.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <fcntl.h>
    16  #include <sys/resource.h>
    17  #include <sys/select.h>
    18  #include <sys/time.h>
    19  
    20  #include <climits>
    21  #include <csignal>
    22  #include <cstdio>
    23  
    24  #include "gtest/gtest.h"
    25  #include "absl/time/time.h"
    26  #include "test/syscalls/linux/base_poll_test.h"
    27  #include "test/util/file_descriptor.h"
    28  #include "test/util/multiprocess_util.h"
    29  #include "test/util/posix_error.h"
    30  #include "test/util/rlimit_util.h"
    31  #include "test/util/temp_path.h"
    32  #include "test/util/test_util.h"
    33  
    34  namespace gvisor {
    35  namespace testing {
    36  namespace {
    37  
    38  class SelectTest : public BasePollTest {
    39   protected:
    40    void SetUp() override { BasePollTest::SetUp(); }
    41    void TearDown() override { BasePollTest::TearDown(); }
    42  };
    43  
    44  // See that when there are no FD sets, select behaves like sleep.
    45  TEST_F(SelectTest, NullFds) {
    46    struct timeval timeout = absl::ToTimeval(absl::Milliseconds(10));
    47    ASSERT_THAT(select(0, nullptr, nullptr, nullptr, &timeout),
    48                SyscallSucceeds());
    49    EXPECT_EQ(timeout.tv_sec, 0);
    50    EXPECT_EQ(timeout.tv_usec, 0);
    51  
    52    timeout = absl::ToTimeval(absl::Milliseconds(10));
    53    ASSERT_THAT(select(1, nullptr, nullptr, nullptr, &timeout),
    54                SyscallSucceeds());
    55    EXPECT_EQ(timeout.tv_sec, 0);
    56    EXPECT_EQ(timeout.tv_usec, 0);
    57  }
    58  
    59  TEST_F(SelectTest, NegativeNfds) {
    60    EXPECT_THAT(select(-1, nullptr, nullptr, nullptr, nullptr),
    61                SyscallFailsWithErrno(EINVAL));
    62    EXPECT_THAT(select(-100000, nullptr, nullptr, nullptr, nullptr),
    63                SyscallFailsWithErrno(EINVAL));
    64    EXPECT_THAT(select(INT_MIN, nullptr, nullptr, nullptr, nullptr),
    65                SyscallFailsWithErrno(EINVAL));
    66  }
    67  
    68  TEST_F(SelectTest, ClosedFds) {
    69    auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    70    FileDescriptor fd =
    71        ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_RDONLY));
    72  
    73    // We can't rely on a file descriptor being closed in a multi threaded
    74    // application so fork to get a clean process.
    75    EXPECT_THAT(InForkedProcess([&] {
    76                  int fd_num = fd.get();
    77                  fd.reset();
    78  
    79                  fd_set read_set;
    80                  FD_ZERO(&read_set);
    81                  FD_SET(fd_num, &read_set);
    82  
    83                  struct timeval timeout =
    84                      absl::ToTimeval(absl::Milliseconds(10));
    85                  TEST_PCHECK(select(fd_num + 1, &read_set, nullptr, nullptr,
    86                                     &timeout) != 0);
    87                  TEST_PCHECK(errno == EBADF);
    88                }),
    89                IsPosixErrorOkAndHolds(0));
    90  }
    91  
    92  TEST_F(SelectTest, ZeroTimeout) {
    93    struct timeval timeout = {};
    94    EXPECT_THAT(select(1, nullptr, nullptr, nullptr, &timeout),
    95                SyscallSucceeds());
    96    // Ignore timeout as its value is now undefined.
    97  }
    98  
    99  // If random S/R interrupts the select, SIGALRM may be delivered before select
   100  // restarts, causing the select to hang forever.
   101  TEST_F(SelectTest, NoTimeout) {
   102    // When there's no timeout, select may never return so set a timer.
   103    SetTimer(absl::Milliseconds(100));
   104    // See that we get interrupted by the timer.
   105    ASSERT_THAT(select(1, nullptr, nullptr, nullptr, nullptr),
   106                SyscallFailsWithErrno(EINTR));
   107    EXPECT_TRUE(TimerFired());
   108  }
   109  
   110  TEST_F(SelectTest, InvalidTimeoutNegative) {
   111    struct timeval timeout = absl::ToTimeval(absl::Microseconds(-1));
   112    EXPECT_THAT(select(1, nullptr, nullptr, nullptr, &timeout),
   113                SyscallFailsWithErrno(EINVAL));
   114    // Ignore timeout as its value is now undefined.
   115  }
   116  
   117  // Verify that a signal interrupts select.
   118  //
   119  // If random S/R interrupts the select, SIGALRM may be delivered before select
   120  // restarts, causing the select to hang forever.
   121  TEST_F(SelectTest, InterruptedBySignal) {
   122    absl::Duration duration(absl::Seconds(5));
   123    struct timeval timeout = absl::ToTimeval(duration);
   124    SetTimer(absl::Milliseconds(100));
   125    ASSERT_FALSE(TimerFired());
   126    ASSERT_THAT(select(1, nullptr, nullptr, nullptr, &timeout),
   127                SyscallFailsWithErrno(EINTR));
   128    EXPECT_TRUE(TimerFired());
   129    // Ignore timeout as its value is now undefined.
   130  }
   131  
   132  TEST_F(SelectTest, IgnoreBitsAboveNfds) {
   133    // fd_set is a bit array with at least FD_SETSIZE bits. Test that bits
   134    // corresponding to file descriptors above nfds are ignored.
   135    fd_set read_set;
   136    FD_ZERO(&read_set);
   137    constexpr int kNfds = 1;
   138    for (int fd = kNfds; fd < FD_SETSIZE; fd++) {
   139      FD_SET(fd, &read_set);
   140    }
   141    // Pass a zero timeout so that select returns immediately.
   142    struct timeval timeout = {};
   143    EXPECT_THAT(select(kNfds, &read_set, nullptr, nullptr, &timeout),
   144                SyscallSucceedsWithValue(0));
   145  }
   146  
   147  // This test illustrates Linux's behavior of 'select' calls passing after
   148  // setrlimit RLIMIT_NOFILE is called. In particular, versions of sshd rely on
   149  // this behavior. See b/122318458.
   150  TEST_F(SelectTest, SetrlimitCallNOFILE) {
   151    fd_set read_set;
   152    FD_ZERO(&read_set);
   153    timeval timeout = {};
   154    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
   155        Open(NewTempAbsPath(), O_RDONLY | O_CREAT, S_IRUSR));
   156  
   157    Cleanup reset_rlimit =
   158        ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_NOFILE, 0));
   159  
   160    FD_SET(fd.get(), &read_set);
   161    // this call with zero timeout should return immediately
   162    EXPECT_THAT(select(fd.get() + 1, &read_set, nullptr, nullptr, &timeout),
   163                SyscallSucceeds());
   164  }
   165  
   166  }  // namespace
   167  }  // namespace testing
   168  }  // namespace gvisor