gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/readv.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 <errno.h>
    16  #include <fcntl.h>
    17  #include <limits.h>
    18  #include <sys/types.h>
    19  #include <unistd.h>
    20  
    21  #include "gtest/gtest.h"
    22  #include "test/syscalls/linux/file_base.h"
    23  #include "test/syscalls/linux/readv_common.h"
    24  #include "test/util/file_descriptor.h"
    25  #include "test/util/temp_path.h"
    26  #include "test/util/test_util.h"
    27  #include "test/util/timer_util.h"
    28  
    29  namespace gvisor {
    30  namespace testing {
    31  
    32  namespace {
    33  
    34  class ReadvTest : public FileTest {
    35    void SetUp() override {
    36      FileTest::SetUp();
    37  
    38      ASSERT_THAT(write(test_file_fd_.get(), kReadvTestData, kReadvTestDataSize),
    39                  SyscallSucceedsWithValue(kReadvTestDataSize));
    40      ASSERT_THAT(lseek(test_file_fd_.get(), 0, SEEK_SET),
    41                  SyscallSucceedsWithValue(0));
    42      ASSERT_THAT(write(test_pipe_[1], kReadvTestData, kReadvTestDataSize),
    43                  SyscallSucceedsWithValue(kReadvTestDataSize));
    44    }
    45  };
    46  
    47  TEST_F(ReadvTest, ReadOneBufferPerByte_File) {
    48    ReadOneBufferPerByte(test_file_fd_.get());
    49  }
    50  
    51  TEST_F(ReadvTest, ReadOneBufferPerByte_Pipe) {
    52    ReadOneBufferPerByte(test_pipe_[0]);
    53  }
    54  
    55  TEST_F(ReadvTest, ReadOneHalfAtATime_File) {
    56    ReadOneHalfAtATime(test_file_fd_.get());
    57  }
    58  
    59  TEST_F(ReadvTest, ReadOneHalfAtATime_Pipe) {
    60    ReadOneHalfAtATime(test_pipe_[0]);
    61  }
    62  
    63  TEST_F(ReadvTest, ReadAllOneBuffer_File) {
    64    ReadAllOneBuffer(test_file_fd_.get());
    65  }
    66  
    67  TEST_F(ReadvTest, ReadAllOneBuffer_Pipe) { ReadAllOneBuffer(test_pipe_[0]); }
    68  
    69  TEST_F(ReadvTest, ReadAllOneLargeBuffer_File) {
    70    ReadAllOneLargeBuffer(test_file_fd_.get());
    71  }
    72  
    73  TEST_F(ReadvTest, ReadAllOneLargeBuffer_Pipe) {
    74    ReadAllOneLargeBuffer(test_pipe_[0]);
    75  }
    76  
    77  TEST_F(ReadvTest, ReadBuffersOverlapping_File) {
    78    ReadBuffersOverlapping(test_file_fd_.get());
    79  }
    80  
    81  TEST_F(ReadvTest, ReadBuffersOverlapping_Pipe) {
    82    ReadBuffersOverlapping(test_pipe_[0]);
    83  }
    84  
    85  TEST_F(ReadvTest, ReadBuffersDiscontinuous_File) {
    86    ReadBuffersDiscontinuous(test_file_fd_.get());
    87  }
    88  
    89  TEST_F(ReadvTest, ReadBuffersDiscontinuous_Pipe) {
    90    ReadBuffersDiscontinuous(test_pipe_[0]);
    91  }
    92  
    93  TEST_F(ReadvTest, ReadIovecsCompletelyFilled_File) {
    94    ReadIovecsCompletelyFilled(test_file_fd_.get());
    95  }
    96  
    97  TEST_F(ReadvTest, ReadIovecsCompletelyFilled_Pipe) {
    98    ReadIovecsCompletelyFilled(test_pipe_[0]);
    99  }
   100  
   101  TEST_F(ReadvTest, BadFileDescriptor) {
   102    char buffer[1024];
   103    struct iovec iov[1];
   104    iov[0].iov_base = buffer;
   105    iov[0].iov_len = 1024;
   106  
   107    ASSERT_THAT(readv(-1, iov, 1), SyscallFailsWithErrno(EBADF));
   108  }
   109  TEST_F(ReadvTest, BadIovecsPointer_File) {
   110  #pragma GCC diagnostic push
   111  #pragma GCC diagnostic ignored "-Wnonnull"
   112    ASSERT_THAT(readv(test_file_fd_.get(), nullptr, 1),
   113                SyscallFailsWithErrno(EFAULT));
   114  #pragma GCC diagnostic pop
   115  }
   116  
   117  TEST_F(ReadvTest, BadIovecsPointer_Pipe) {
   118  #pragma GCC diagnostic push
   119  #pragma GCC diagnostic ignored "-Wnonnull"
   120    ASSERT_THAT(readv(test_pipe_[0], nullptr, 1), SyscallFailsWithErrno(EFAULT));
   121  #pragma GCC diagnostic pop
   122  }
   123  
   124  TEST_F(ReadvTest, BadIovecBase_File) {
   125    struct iovec iov[1];
   126    iov[0].iov_base = nullptr;
   127    iov[0].iov_len = 1024;
   128    ASSERT_THAT(readv(test_file_fd_.get(), iov, 1),
   129                SyscallFailsWithErrno(EFAULT));
   130  }
   131  
   132  TEST_F(ReadvTest, BadIovecBase_Pipe) {
   133    struct iovec iov[1];
   134    iov[0].iov_base = nullptr;
   135    iov[0].iov_len = 1024;
   136    ASSERT_THAT(readv(test_pipe_[0], iov, 1), SyscallFailsWithErrno(EFAULT));
   137  }
   138  
   139  TEST_F(ReadvTest, ZeroIovecs_File) {
   140    struct iovec iov[1];
   141    iov[0].iov_base = 0;
   142    iov[0].iov_len = 0;
   143    ASSERT_THAT(readv(test_file_fd_.get(), iov, 1), SyscallSucceeds());
   144  }
   145  
   146  TEST_F(ReadvTest, ZeroIovecs_Pipe) {
   147    struct iovec iov[1];
   148    iov[0].iov_base = 0;
   149    iov[0].iov_len = 0;
   150    ASSERT_THAT(readv(test_pipe_[0], iov, 1), SyscallSucceeds());
   151  }
   152  
   153  TEST_F(ReadvTest, NotReadable_File) {
   154    char buffer[1024];
   155    struct iovec iov[1];
   156    iov[0].iov_base = buffer;
   157    iov[0].iov_len = 1024;
   158  
   159    std::string wronly_file = NewTempAbsPath();
   160    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
   161        Open(wronly_file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR));
   162    ASSERT_THAT(readv(fd.get(), iov, 1), SyscallFailsWithErrno(EBADF));
   163    fd.reset();  // Close before unlinking.
   164    ASSERT_THAT(unlink(wronly_file.c_str()), SyscallSucceeds());
   165  }
   166  
   167  TEST_F(ReadvTest, NotReadable_Pipe) {
   168    char buffer[1024];
   169    struct iovec iov[1];
   170    iov[0].iov_base = buffer;
   171    iov[0].iov_len = 1024;
   172    ASSERT_THAT(readv(test_pipe_[1], iov, 1), SyscallFailsWithErrno(EBADF));
   173  }
   174  
   175  TEST_F(ReadvTest, DirNotReadable) {
   176    char buffer[1024];
   177    struct iovec iov[1];
   178    iov[0].iov_base = buffer;
   179    iov[0].iov_len = 1024;
   180  
   181    const FileDescriptor fd =
   182        ASSERT_NO_ERRNO_AND_VALUE(Open(GetAbsoluteTestTmpdir(), O_RDONLY));
   183    ASSERT_THAT(readv(fd.get(), iov, 1), SyscallFailsWithErrno(EISDIR));
   184  }
   185  
   186  TEST_F(ReadvTest, OffsetIncremented) {
   187    char* buffer = reinterpret_cast<char*>(malloc(kReadvTestDataSize));
   188    struct iovec iov[1];
   189    iov[0].iov_base = buffer;
   190    iov[0].iov_len = kReadvTestDataSize;
   191  
   192    ASSERT_THAT(readv(test_file_fd_.get(), iov, 1),
   193                SyscallSucceedsWithValue(kReadvTestDataSize));
   194    ASSERT_THAT(lseek(test_file_fd_.get(), 0, SEEK_CUR),
   195                SyscallSucceedsWithValue(kReadvTestDataSize));
   196  
   197    free(buffer);
   198  }
   199  
   200  TEST_F(ReadvTest, EndOfFile) {
   201    char* buffer = reinterpret_cast<char*>(malloc(kReadvTestDataSize));
   202    struct iovec iov[1];
   203    iov[0].iov_base = buffer;
   204    iov[0].iov_len = kReadvTestDataSize;
   205    ASSERT_THAT(readv(test_file_fd_.get(), iov, 1),
   206                SyscallSucceedsWithValue(kReadvTestDataSize));
   207    free(buffer);
   208  
   209    buffer = reinterpret_cast<char*>(malloc(kReadvTestDataSize));
   210    iov[0].iov_base = buffer;
   211    iov[0].iov_len = kReadvTestDataSize;
   212    ASSERT_THAT(readv(test_file_fd_.get(), iov, 1), SyscallSucceedsWithValue(0));
   213    free(buffer);
   214  }
   215  
   216  TEST_F(ReadvTest, WouldBlock_Pipe) {
   217    struct iovec iov[1];
   218    iov[0].iov_base = reinterpret_cast<char*>(malloc(kReadvTestDataSize));
   219    iov[0].iov_len = kReadvTestDataSize;
   220    ASSERT_THAT(readv(test_pipe_[0], iov, 1),
   221                SyscallSucceedsWithValue(kReadvTestDataSize));
   222    free(iov[0].iov_base);
   223  
   224    iov[0].iov_base = reinterpret_cast<char*>(malloc(kReadvTestDataSize));
   225    ASSERT_THAT(readv(test_pipe_[0], iov, 1), SyscallFailsWithErrno(EAGAIN));
   226    free(iov[0].iov_base);
   227  }
   228  
   229  TEST_F(ReadvTest, ZeroBuffer) {
   230    char buf[10];
   231    struct iovec iov[1];
   232    iov[0].iov_base = buf;
   233    iov[0].iov_len = 0;
   234    ASSERT_THAT(readv(test_pipe_[0], iov, 1), SyscallSucceedsWithValue(0));
   235  }
   236  
   237  TEST_F(ReadvTest, NullIovecInNonemptyArray) {
   238    std::vector<char> buf(kReadvTestDataSize);
   239    struct iovec iov[2];
   240    iov[0].iov_base = nullptr;
   241    iov[0].iov_len = 0;
   242    iov[1].iov_base = buf.data();
   243    iov[1].iov_len = kReadvTestDataSize;
   244    ASSERT_THAT(readv(test_file_fd_.get(), iov, 2),
   245                SyscallSucceedsWithValue(kReadvTestDataSize));
   246  }
   247  
   248  TEST_F(ReadvTest, IovecOutsideTaskAddressRangeInNonemptyArray) {
   249    std::vector<char> buf(kReadvTestDataSize);
   250    struct iovec iov[2];
   251    iov[0].iov_base = reinterpret_cast<void*>(~static_cast<uintptr_t>(0));
   252    iov[0].iov_len = 0;
   253    iov[1].iov_base = buf.data();
   254    iov[1].iov_len = kReadvTestDataSize;
   255    ASSERT_THAT(readv(test_file_fd_.get(), iov, 2),
   256                SyscallFailsWithErrno(EFAULT));
   257  }
   258  
   259  TEST_F(ReadvTest, ReadvWithOpath) {
   260    char buffer[1024];
   261    struct iovec iov[1];
   262    iov[0].iov_base = buffer;
   263    iov[0].iov_len = 1024;
   264  
   265    TempPath tmpfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   266    FileDescriptor fd =
   267        ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfile.path().c_str(), O_PATH));
   268  
   269    ASSERT_THAT(readv(fd.get(), iov, 1), SyscallFailsWithErrno(EBADF));
   270  }
   271  
   272  // This test depends on the maximum extent of a single readv() syscall, so
   273  // we can't tolerate interruption from saving.
   274  TEST(ReadvTestNoFixture, TruncatedAtMax) {
   275    // Ensure that we won't be interrupted by ITIMER_PROF. This is particularly
   276    // important in environments where automated profiling tools may start
   277    // ITIMER_PROF automatically.
   278    struct itimerval itv = {};
   279    auto const cleanup_itimer =
   280        ASSERT_NO_ERRNO_AND_VALUE(ScopedItimer(ITIMER_PROF, itv));
   281  
   282    // From Linux's include/linux/fs.h.
   283    size_t const MAX_RW_COUNT = INT_MAX & ~(kPageSize - 1);
   284  
   285    // Create an iovec array with 3 segments pointing to consecutive parts of a
   286    // buffer. The first covers all but the last three pages, and should be
   287    // written to in its entirety. The second covers the last page before
   288    // MAX_RW_COUNT and the first page after; only the first page should be
   289    // written to. The third covers the last page of the buffer, and should be
   290    // skipped entirely.
   291    size_t const kBufferSize = MAX_RW_COUNT + 2 * kPageSize;
   292    size_t const kFirstOffset = MAX_RW_COUNT - kPageSize;
   293    size_t const kSecondOffset = MAX_RW_COUNT + kPageSize;
   294    // The buffer is too big to fit on the stack.
   295    std::vector<char> buf(kBufferSize);
   296    struct iovec iov[3];
   297    iov[0].iov_base = buf.data();
   298    iov[0].iov_len = kFirstOffset;
   299    iov[1].iov_base = buf.data() + kFirstOffset;
   300    iov[1].iov_len = kSecondOffset - kFirstOffset;
   301    iov[2].iov_base = buf.data() + kSecondOffset;
   302    iov[2].iov_len = kBufferSize - kSecondOffset;
   303  
   304    const FileDescriptor fd =
   305        ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/zero", O_RDONLY));
   306    EXPECT_THAT(readv(fd.get(), iov, 3), SyscallSucceedsWithValue(MAX_RW_COUNT));
   307  }
   308  
   309  }  // namespace
   310  
   311  }  // namespace testing
   312  }  // namespace gvisor