gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/pipe.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> /* Obtain O_* constant definitions */
    17  #include <linux/futex.h>
    18  #include <linux/magic.h>
    19  #include <signal.h>
    20  #include <sys/ioctl.h>
    21  #include <sys/statfs.h>
    22  #include <sys/uio.h>
    23  #include <syscall.h>
    24  #include <unistd.h>
    25  
    26  #include <vector>
    27  
    28  #include "gtest/gtest.h"
    29  #include "absl/strings/str_cat.h"
    30  #include "absl/synchronization/notification.h"
    31  #include "absl/time/clock.h"
    32  #include "absl/time/time.h"
    33  #include "test/util/file_descriptor.h"
    34  #include "test/util/fs_util.h"
    35  #include "test/util/posix_error.h"
    36  #include "test/util/save_util.h"
    37  #include "test/util/signal_util.h"
    38  #include "test/util/temp_path.h"
    39  #include "test/util/test_util.h"
    40  #include "test/util/thread_util.h"
    41  
    42  namespace gvisor {
    43  namespace testing {
    44  
    45  namespace {
    46  
    47  // Used as a non-zero sentinel value, below.
    48  constexpr int kTestValue = 0x12345678;
    49  
    50  // Used for synchronization in race tests.
    51  const absl::Duration syncDelay = absl::Seconds(2);
    52  
    53  std::atomic<int> global_num_signals_received = 0;
    54  void SigRecordingHandler(int signum, siginfo_t* siginfo,
    55                           void* unused_ucontext) {
    56    global_num_signals_received++;
    57    ASSERT_THAT(syscall(SYS_futex, &global_num_signals_received,
    58                        FUTEX_WAKE | FUTEX_PRIVATE_FLAG, INT_MAX, 0, 0, 0),
    59                SyscallSucceeds());
    60  }
    61  
    62  PosixErrorOr<Cleanup> RegisterSignalHandler(int signum) {
    63    global_num_signals_received = 0;
    64    struct sigaction handler;
    65    handler.sa_sigaction = SigRecordingHandler;
    66    sigemptyset(&handler.sa_mask);
    67    handler.sa_flags = SA_SIGINFO;
    68    return ScopedSigaction(signum, handler);
    69  }
    70  
    71  void WaitForSignalDelivery(int expected) {
    72    while (1) {
    73      int v = global_num_signals_received;
    74      if (v >= expected) {
    75        break;
    76      }
    77      RetryEINTR(syscall)(SYS_futex, &global_num_signals_received,
    78                          FUTEX_WAIT | FUTEX_PRIVATE_FLAG, v, 0, 0, 0);
    79    }
    80  }
    81  
    82  struct PipeCreator {
    83    std::string name_;
    84  
    85    // void (fds, is_blocking, is_namedpipe).
    86    std::function<void(int[2], bool*, bool*)> create_;
    87  };
    88  
    89  class PipeTest : public ::testing::TestWithParam<PipeCreator> {
    90   public:
    91    static void SetUpTestSuite() {
    92      // Tests intentionally generate SIGPIPE.
    93      TEST_PCHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
    94    }
    95  
    96    // Initializes rfd_ and wfd_ as a blocking pipe.
    97    //
    98    // The return value indicates success: the test should be skipped otherwise.
    99    bool CreateBlocking() { return create(true); }
   100  
   101    // Initializes rfd_ and wfd_ as a non-blocking pipe.
   102    //
   103    // The return value is per CreateBlocking.
   104    bool CreateNonBlocking() { return create(false); }
   105  
   106    // Returns true iff the pipe represents a named pipe.
   107    bool IsNamedPipe() const { return named_pipe_; }
   108  
   109    size_t Size() const {
   110      int s1 = fcntl(rfd_.get(), F_GETPIPE_SZ);
   111      int s2 = fcntl(wfd_.get(), F_GETPIPE_SZ);
   112      EXPECT_GT(s1, 0);
   113      EXPECT_GT(s2, 0);
   114      EXPECT_EQ(s1, s2);
   115      return static_cast<size_t>(s1);
   116    }
   117  
   118    static void TearDownTestSuite() {
   119      TEST_PCHECK(signal(SIGPIPE, SIG_DFL) != SIG_ERR);
   120    }
   121  
   122   private:
   123    bool create(bool wants_blocking) {
   124      // Generate the pipe.
   125      int fds[2] = {-1, -1};
   126      bool is_blocking = false;
   127      GetParam().create_(fds, &is_blocking, &named_pipe_);
   128      if (fds[0] < 0 || fds[1] < 0) {
   129        return false;
   130      }
   131  
   132      // Save descriptors.
   133      rfd_.reset(fds[0]);
   134      wfd_.reset(fds[1]);
   135  
   136      // Adjust blocking, if needed.
   137      if (!is_blocking && wants_blocking) {
   138        // Clear the blocking flag.
   139        EXPECT_THAT(fcntl(fds[0], F_SETFL, 0), SyscallSucceeds());
   140        EXPECT_THAT(fcntl(fds[1], F_SETFL, 0), SyscallSucceeds());
   141      } else if (is_blocking && !wants_blocking) {
   142        // Set the descriptors to blocking.
   143        EXPECT_THAT(fcntl(fds[0], F_SETFL, O_NONBLOCK), SyscallSucceeds());
   144        EXPECT_THAT(fcntl(fds[1], F_SETFL, O_NONBLOCK), SyscallSucceeds());
   145      }
   146  
   147      return true;
   148    }
   149  
   150   protected:
   151    FileDescriptor rfd_;
   152    FileDescriptor wfd_;
   153  
   154   private:
   155    bool named_pipe_ = false;
   156  };
   157  
   158  TEST_P(PipeTest, Inode) {
   159    SKIP_IF(!CreateBlocking());
   160  
   161    // Ensure that the inode number is the same for each end.
   162    struct stat rst;
   163    ASSERT_THAT(fstat(rfd_.get(), &rst), SyscallSucceeds());
   164    struct stat wst;
   165    ASSERT_THAT(fstat(wfd_.get(), &wst), SyscallSucceeds());
   166    EXPECT_EQ(rst.st_ino, wst.st_ino);
   167  }
   168  
   169  TEST_P(PipeTest, Permissions) {
   170    SKIP_IF(!CreateBlocking());
   171  
   172    // Attempt bad operations.
   173    int buf = kTestValue;
   174    ASSERT_THAT(write(rfd_.get(), &buf, sizeof(buf)),
   175                SyscallFailsWithErrno(EBADF));
   176    EXPECT_THAT(read(wfd_.get(), &buf, sizeof(buf)),
   177                SyscallFailsWithErrno(EBADF));
   178  }
   179  
   180  TEST_P(PipeTest, Flags) {
   181    SKIP_IF(!CreateBlocking());
   182  
   183    if (IsNamedPipe()) {
   184      // May be stubbed to zero; define locally.
   185      EXPECT_THAT(fcntl(rfd_.get(), F_GETFL),
   186                  SyscallSucceedsWithValue(kOLargeFile | O_RDONLY));
   187      EXPECT_THAT(fcntl(wfd_.get(), F_GETFL),
   188                  SyscallSucceedsWithValue(kOLargeFile | O_WRONLY));
   189    } else {
   190      EXPECT_THAT(fcntl(rfd_.get(), F_GETFL), SyscallSucceedsWithValue(O_RDONLY));
   191      EXPECT_THAT(fcntl(wfd_.get(), F_GETFL), SyscallSucceedsWithValue(O_WRONLY));
   192    }
   193  }
   194  
   195  TEST_P(PipeTest, Write) {
   196    SKIP_IF(!CreateBlocking());
   197  
   198    int wbuf = kTestValue;
   199    int rbuf = ~kTestValue;
   200    ASSERT_THAT(write(wfd_.get(), &wbuf, sizeof(wbuf)),
   201                SyscallSucceedsWithValue(sizeof(wbuf)));
   202    ASSERT_THAT(read(rfd_.get(), &rbuf, sizeof(rbuf)),
   203                SyscallSucceedsWithValue(sizeof(rbuf)));
   204    EXPECT_EQ(wbuf, rbuf);
   205  }
   206  
   207  TEST_P(PipeTest, WritePage) {
   208    SKIP_IF(!CreateBlocking());
   209  
   210    std::vector<char> wbuf(kPageSize);
   211    RandomizeBuffer(wbuf.data(), wbuf.size());
   212    std::vector<char> rbuf(wbuf.size());
   213  
   214    ASSERT_THAT(write(wfd_.get(), wbuf.data(), wbuf.size()),
   215                SyscallSucceedsWithValue(wbuf.size()));
   216    ASSERT_THAT(read(rfd_.get(), rbuf.data(), rbuf.size()),
   217                SyscallSucceedsWithValue(rbuf.size()));
   218    EXPECT_EQ(memcmp(rbuf.data(), wbuf.data(), wbuf.size()), 0);
   219  }
   220  
   221  TEST_P(PipeTest, NonBlocking) {
   222    SKIP_IF(!CreateNonBlocking());
   223  
   224    int wbuf = kTestValue;
   225    int rbuf = ~kTestValue;
   226    EXPECT_THAT(read(rfd_.get(), &rbuf, sizeof(rbuf)),
   227                SyscallFailsWithErrno(EWOULDBLOCK));
   228    ASSERT_THAT(write(wfd_.get(), &wbuf, sizeof(wbuf)),
   229                SyscallSucceedsWithValue(sizeof(wbuf)));
   230  
   231    ASSERT_THAT(read(rfd_.get(), &rbuf, sizeof(rbuf)),
   232                SyscallSucceedsWithValue(sizeof(rbuf)));
   233    EXPECT_EQ(wbuf, rbuf);
   234    EXPECT_THAT(read(rfd_.get(), &rbuf, sizeof(rbuf)),
   235                SyscallFailsWithErrno(EWOULDBLOCK));
   236  }
   237  
   238  TEST(PipeTest, StatFS) {
   239    int fds[2];
   240    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   241    struct statfs st;
   242    EXPECT_THAT(fstatfs(fds[0], &st), SyscallSucceeds());
   243    EXPECT_EQ(st.f_type, PIPEFS_MAGIC);
   244    EXPECT_EQ(st.f_bsize, getpagesize());
   245    EXPECT_EQ(st.f_namelen, NAME_MAX);
   246  }
   247  
   248  TEST(Pipe2Test, CloExec) {
   249    int fds[2];
   250    ASSERT_THAT(pipe2(fds, O_CLOEXEC), SyscallSucceeds());
   251    EXPECT_THAT(fcntl(fds[0], F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC));
   252    EXPECT_THAT(fcntl(fds[1], F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC));
   253    EXPECT_THAT(close(fds[0]), SyscallSucceeds());
   254    EXPECT_THAT(close(fds[1]), SyscallSucceeds());
   255  }
   256  
   257  TEST(Pipe2Test, BadOptions) {
   258    int fds[2];
   259    EXPECT_THAT(pipe2(fds, 0xDEAD), SyscallFailsWithErrno(EINVAL));
   260  }
   261  
   262  // Tests that opening named pipes with O_TRUNC shouldn't cause an error, but
   263  // calls to (f)truncate should.
   264  TEST(NamedPipeTest, Truncate) {
   265    const std::string tmp_path = NewTempAbsPath();
   266    SKIP_IF(mkfifo(tmp_path.c_str(), 0644) != 0);
   267  
   268    ASSERT_THAT(open(tmp_path.c_str(), O_NONBLOCK | O_RDONLY), SyscallSucceeds());
   269    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
   270        Open(tmp_path.c_str(), O_RDWR | O_NONBLOCK | O_TRUNC));
   271  
   272    ASSERT_THAT(truncate(tmp_path.c_str(), 0), SyscallFailsWithErrno(EINVAL));
   273    ASSERT_THAT(ftruncate(fd.get(), 0), SyscallFailsWithErrno(EINVAL));
   274  }
   275  
   276  TEST_P(PipeTest, Seek) {
   277    SKIP_IF(!CreateBlocking());
   278  
   279    for (int i = 0; i < 4; i++) {
   280      // Saving after each failed lseek() is too expensive for the testing
   281      // benefit, especially in a loop.
   282      {
   283        DisableSave ds;
   284        // Attempt absolute seeks.
   285        EXPECT_THAT(lseek(rfd_.get(), 0, SEEK_SET),
   286                    SyscallFailsWithErrno(ESPIPE));
   287        EXPECT_THAT(lseek(rfd_.get(), 4, SEEK_SET),
   288                    SyscallFailsWithErrno(ESPIPE));
   289        EXPECT_THAT(lseek(wfd_.get(), 0, SEEK_SET),
   290                    SyscallFailsWithErrno(ESPIPE));
   291        EXPECT_THAT(lseek(wfd_.get(), 4, SEEK_SET),
   292                    SyscallFailsWithErrno(ESPIPE));
   293  
   294        // Attempt relative seeks.
   295        EXPECT_THAT(lseek(rfd_.get(), 0, SEEK_CUR),
   296                    SyscallFailsWithErrno(ESPIPE));
   297        EXPECT_THAT(lseek(rfd_.get(), 4, SEEK_CUR),
   298                    SyscallFailsWithErrno(ESPIPE));
   299        EXPECT_THAT(lseek(wfd_.get(), 0, SEEK_CUR),
   300                    SyscallFailsWithErrno(ESPIPE));
   301        EXPECT_THAT(lseek(wfd_.get(), 4, SEEK_CUR),
   302                    SyscallFailsWithErrno(ESPIPE));
   303  
   304        // Attempt end-of-file seeks.
   305        EXPECT_THAT(lseek(rfd_.get(), 0, SEEK_CUR),
   306                    SyscallFailsWithErrno(ESPIPE));
   307        EXPECT_THAT(lseek(rfd_.get(), -4, SEEK_END),
   308                    SyscallFailsWithErrno(ESPIPE));
   309        EXPECT_THAT(lseek(wfd_.get(), 0, SEEK_CUR),
   310                    SyscallFailsWithErrno(ESPIPE));
   311        EXPECT_THAT(lseek(wfd_.get(), -4, SEEK_END),
   312                    SyscallFailsWithErrno(ESPIPE));
   313      }
   314      MaybeSave();
   315  
   316      // Add some more data to the pipe.
   317      int buf = kTestValue;
   318      ASSERT_THAT(write(wfd_.get(), &buf, sizeof(buf)),
   319                  SyscallSucceedsWithValue(sizeof(buf)));
   320    }
   321  }
   322  
   323  #ifndef ANDROID
   324  // Android does not support preadv or pwritev in r22.
   325  
   326  TEST_P(PipeTest, OffsetCalls) {
   327    SKIP_IF(!CreateBlocking());
   328  
   329    int buf;
   330    EXPECT_THAT(pread(wfd_.get(), &buf, sizeof(buf), 0),
   331                SyscallFailsWithErrno(ESPIPE));
   332    EXPECT_THAT(pwrite(rfd_.get(), &buf, sizeof(buf), 0),
   333                SyscallFailsWithErrno(ESPIPE));
   334  
   335    struct iovec iov;
   336    iov.iov_base = &buf;
   337    iov.iov_len = sizeof(buf);
   338    EXPECT_THAT(preadv(wfd_.get(), &iov, 1, 0), SyscallFailsWithErrno(ESPIPE));
   339    EXPECT_THAT(pwritev(rfd_.get(), &iov, 1, 0), SyscallFailsWithErrno(ESPIPE));
   340  }
   341  
   342  #endif  // ANDROID
   343  
   344  TEST_P(PipeTest, WriterSideCloses) {
   345    SKIP_IF(!CreateBlocking());
   346  
   347    ScopedThread t([this]() {
   348      int buf = ~kTestValue;
   349      ASSERT_THAT(read(rfd_.get(), &buf, sizeof(buf)),
   350                  SyscallSucceedsWithValue(sizeof(buf)));
   351      EXPECT_EQ(buf, kTestValue);
   352      // This will return when the close() completes.
   353      ASSERT_THAT(read(rfd_.get(), &buf, sizeof(buf)), SyscallSucceeds());
   354      // This will return straight away.
   355      ASSERT_THAT(read(rfd_.get(), &buf, sizeof(buf)),
   356                  SyscallSucceedsWithValue(0));
   357    });
   358  
   359    // Sleep a bit so the thread can block.
   360    absl::SleepFor(syncDelay);
   361  
   362    // Write to unblock.
   363    int buf = kTestValue;
   364    ASSERT_THAT(write(wfd_.get(), &buf, sizeof(buf)),
   365                SyscallSucceedsWithValue(sizeof(buf)));
   366  
   367    // Sleep a bit so the thread can block again.
   368    absl::SleepFor(syncDelay);
   369  
   370    // Allow the thread to complete.
   371    ASSERT_THAT(close(wfd_.release()), SyscallSucceeds());
   372    t.Join();
   373  }
   374  
   375  TEST_P(PipeTest, WriterSideClosesReadDataFirst) {
   376    SKIP_IF(!CreateBlocking());
   377  
   378    int wbuf = kTestValue;
   379    ASSERT_THAT(write(wfd_.get(), &wbuf, sizeof(wbuf)),
   380                SyscallSucceedsWithValue(sizeof(wbuf)));
   381    ASSERT_THAT(close(wfd_.release()), SyscallSucceeds());
   382  
   383    int rbuf;
   384    ASSERT_THAT(read(rfd_.get(), &rbuf, sizeof(rbuf)),
   385                SyscallSucceedsWithValue(sizeof(rbuf)));
   386    EXPECT_EQ(wbuf, rbuf);
   387    EXPECT_THAT(read(rfd_.get(), &rbuf, sizeof(rbuf)),
   388                SyscallSucceedsWithValue(0));
   389  }
   390  
   391  TEST_P(PipeTest, ReaderSideCloses) {
   392    SKIP_IF(!CreateBlocking());
   393  
   394    const auto signal_cleanup =
   395        ASSERT_NO_ERRNO_AND_VALUE(RegisterSignalHandler(SIGPIPE));
   396  
   397    ASSERT_THAT(close(rfd_.release()), SyscallSucceeds());
   398    int buf = kTestValue;
   399    EXPECT_THAT(write(wfd_.get(), &buf, sizeof(buf)),
   400                SyscallFailsWithErrno(EPIPE));
   401  
   402    WaitForSignalDelivery(1);
   403    ASSERT_EQ(global_num_signals_received, 1);
   404  }
   405  
   406  TEST_P(PipeTest, CloseTwice) {
   407    SKIP_IF(!CreateBlocking());
   408  
   409    int reader = rfd_.release();
   410    int writer = wfd_.release();
   411    ASSERT_THAT(close(reader), SyscallSucceeds());
   412    ASSERT_THAT(close(writer), SyscallSucceeds());
   413    EXPECT_THAT(close(reader), SyscallFailsWithErrno(EBADF));
   414    EXPECT_THAT(close(writer), SyscallFailsWithErrno(EBADF));
   415  }
   416  
   417  // Blocking write returns EPIPE when read end is closed if nothing has been
   418  // written.
   419  TEST_P(PipeTest, BlockWriteClosed) {
   420    SKIP_IF(!CreateBlocking());
   421  
   422    const auto signal_cleanup =
   423        ASSERT_NO_ERRNO_AND_VALUE(RegisterSignalHandler(SIGPIPE));
   424  
   425    absl::Notification notify;
   426    ScopedThread t([this, &notify]() {
   427      std::vector<char> buf(Size());
   428      // Exactly fill the pipe buffer.
   429      ASSERT_THAT(WriteFd(wfd_.get(), buf.data(), buf.size()),
   430                  SyscallSucceedsWithValue(buf.size()));
   431  
   432      notify.Notify();
   433  
   434      // Attempt to write one more byte. Blocks.
   435      // N.B. Don't use WriteFd, we don't want a retry.
   436      EXPECT_THAT(write(wfd_.get(), buf.data(), 1), SyscallFailsWithErrno(EPIPE));
   437    });
   438  
   439    notify.WaitForNotification();
   440    ASSERT_THAT(close(rfd_.release()), SyscallSucceeds());
   441  
   442    WaitForSignalDelivery(1);
   443    ASSERT_EQ(global_num_signals_received, 1);
   444  
   445    t.Join();
   446  }
   447  
   448  // Blocking write returns EPIPE when read end is closed even if something has
   449  // been written.
   450  TEST_P(PipeTest, BlockPartialWriteClosed) {
   451    SKIP_IF(!CreateBlocking());
   452  
   453    const auto signal_cleanup =
   454        ASSERT_NO_ERRNO_AND_VALUE(RegisterSignalHandler(SIGPIPE));
   455  
   456    ScopedThread t([this]() {
   457      const int pipe_size = Size();
   458      std::vector<char> buf(2 * pipe_size);
   459  
   460      // Write more than fits in the buffer. Blocks then returns partial write
   461      // when the other end is closed. The next call returns EPIPE.
   462      ASSERT_THAT(write(wfd_.get(), buf.data(), buf.size()),
   463                  SyscallSucceedsWithValue(pipe_size));
   464      EXPECT_THAT(write(wfd_.get(), buf.data(), buf.size()),
   465                  SyscallFailsWithErrno(EPIPE));
   466    });
   467  
   468    // Leave time for write to become blocked.
   469    absl::SleepFor(syncDelay);
   470  
   471    // Unblock the above.
   472    ASSERT_THAT(close(rfd_.release()), SyscallSucceeds());
   473  
   474    WaitForSignalDelivery(2);
   475    ASSERT_EQ(global_num_signals_received, 2);
   476  
   477    t.Join();
   478  }
   479  
   480  TEST_P(PipeTest, ReadFromClosedFd) {
   481    SKIP_IF(!CreateBlocking());
   482  
   483    absl::Notification notify;
   484    ScopedThread t([this, &notify]() {
   485      notify.Notify();
   486      int buf;
   487      ASSERT_THAT(read(rfd_.get(), &buf, sizeof(buf)),
   488                  SyscallSucceedsWithValue(sizeof(buf)));
   489      ASSERT_EQ(kTestValue, buf);
   490    });
   491    notify.WaitForNotification();
   492  
   493    // Make sure that the thread gets to read().
   494    absl::SleepFor(syncDelay);
   495  
   496    {
   497      // We cannot save/restore here as the read end of pipe is closed but there
   498      // is ongoing read() above. We will not be able to restart the read()
   499      // successfully in restore run since the read fd is closed.
   500      const DisableSave ds;
   501      ASSERT_THAT(close(rfd_.release()), SyscallSucceeds());
   502      int buf = kTestValue;
   503      ASSERT_THAT(write(wfd_.get(), &buf, sizeof(buf)),
   504                  SyscallSucceedsWithValue(sizeof(buf)));
   505      t.Join();
   506    }
   507  }
   508  
   509  TEST_P(PipeTest, FionRead) {
   510    SKIP_IF(!CreateBlocking());
   511  
   512    int n;
   513    ASSERT_THAT(ioctl(rfd_.get(), FIONREAD, &n), SyscallSucceedsWithValue(0));
   514    EXPECT_EQ(n, 0);
   515    ASSERT_THAT(ioctl(wfd_.get(), FIONREAD, &n), SyscallSucceedsWithValue(0));
   516    EXPECT_EQ(n, 0);
   517  
   518    std::vector<char> buf(Size());
   519    ASSERT_THAT(write(wfd_.get(), buf.data(), buf.size()),
   520                SyscallSucceedsWithValue(buf.size()));
   521  
   522    EXPECT_THAT(ioctl(rfd_.get(), FIONREAD, &n), SyscallSucceedsWithValue(0));
   523    EXPECT_EQ(n, buf.size());
   524    EXPECT_THAT(ioctl(wfd_.get(), FIONREAD, &n), SyscallSucceedsWithValue(0));
   525    EXPECT_EQ(n, buf.size());
   526  }
   527  
   528  // Test that opening an empty anonymous pipe RDONLY via /proc/self/fd/N does not
   529  // block waiting for a writer.
   530  TEST_P(PipeTest, OpenViaProcSelfFD) {
   531    SKIP_IF(!CreateBlocking());
   532    SKIP_IF(IsNamedPipe());
   533  
   534    // Close the write end of the pipe.
   535    ASSERT_THAT(close(wfd_.release()), SyscallSucceeds());
   536  
   537    // Open other side via /proc/self/fd.  It should not block.
   538    FileDescriptor proc_self_fd = ASSERT_NO_ERRNO_AND_VALUE(
   539        Open(absl::StrCat("/proc/self/fd/", rfd_.get()), O_RDONLY));
   540  }
   541  
   542  // Test that opening and reading from an anonymous pipe (with existing writes)
   543  // RDONLY via /proc/self/fd/N returns the existing data.
   544  TEST_P(PipeTest, OpenViaProcSelfFDWithWrites) {
   545    SKIP_IF(!CreateBlocking());
   546    SKIP_IF(IsNamedPipe());
   547  
   548    // Write to the pipe and then close the write fd.
   549    int wbuf = kTestValue;
   550    ASSERT_THAT(write(wfd_.get(), &wbuf, sizeof(wbuf)),
   551                SyscallSucceedsWithValue(sizeof(wbuf)));
   552    ASSERT_THAT(close(wfd_.release()), SyscallSucceeds());
   553  
   554    // Open read side via /proc/self/fd, and read from it.
   555    FileDescriptor proc_self_fd = ASSERT_NO_ERRNO_AND_VALUE(
   556        Open(absl::StrCat("/proc/self/fd/", rfd_.get()), O_RDONLY));
   557    int rbuf;
   558    ASSERT_THAT(read(proc_self_fd.get(), &rbuf, sizeof(rbuf)),
   559                SyscallSucceedsWithValue(sizeof(rbuf)));
   560    EXPECT_EQ(wbuf, rbuf);
   561  }
   562  
   563  // Test that accesses of /proc/<PID>/fd correctly decrement the refcount.
   564  TEST_P(PipeTest, ProcFDReleasesFile) {
   565    SKIP_IF(!CreateBlocking());
   566  
   567    // Stat the pipe FD, which shouldn't alter the refcount.
   568    struct stat wst;
   569    ASSERT_THAT(lstat(absl::StrCat("/proc/self/fd/", wfd_.get()).c_str(), &wst),
   570                SyscallSucceeds());
   571  
   572    // Close the write end and ensure that read indicates EOF.
   573    wfd_.reset();
   574    char buf;
   575    ASSERT_THAT(read(rfd_.get(), &buf, 1), SyscallSucceedsWithValue(0));
   576  }
   577  
   578  // Same for /proc/<PID>/fdinfo.
   579  TEST_P(PipeTest, ProcFDInfoReleasesFile) {
   580    SKIP_IF(!CreateBlocking());
   581  
   582    // Stat the pipe FD, which shouldn't alter the refcount.
   583    struct stat wst;
   584    ASSERT_THAT(
   585        lstat(absl::StrCat("/proc/self/fdinfo/", wfd_.get()).c_str(), &wst),
   586        SyscallSucceeds());
   587  
   588    // Close the write end and ensure that read indicates EOF.
   589    wfd_.reset();
   590    char buf;
   591    ASSERT_THAT(read(rfd_.get(), &buf, 1), SyscallSucceedsWithValue(0));
   592  }
   593  
   594  TEST_P(PipeTest, SizeChange) {
   595    SKIP_IF(!CreateBlocking());
   596  
   597    // Set the minimum possible size.
   598    ASSERT_THAT(fcntl(rfd_.get(), F_SETPIPE_SZ, 0), SyscallSucceeds());
   599    int min = Size();
   600    EXPECT_GT(min, 0);  // Should be rounded up.
   601  
   602    // Set from the read end.
   603    ASSERT_THAT(fcntl(rfd_.get(), F_SETPIPE_SZ, min + 1), SyscallSucceeds());
   604    int med = Size();
   605    EXPECT_GT(med, min);  // Should have grown, may be rounded.
   606  
   607    // Set from the write end.
   608    ASSERT_THAT(fcntl(wfd_.get(), F_SETPIPE_SZ, med + 1), SyscallSucceeds());
   609    int max = Size();
   610    EXPECT_GT(max, med);  // Ditto.
   611  }
   612  
   613  TEST_P(PipeTest, SizeChangeMax) {
   614    SKIP_IF(!CreateBlocking());
   615  
   616    // Assert there's some maximum.
   617    EXPECT_THAT(fcntl(rfd_.get(), F_SETPIPE_SZ, 0x7fffffffffffffff),
   618                SyscallFailsWithErrno(EINVAL));
   619    EXPECT_THAT(fcntl(wfd_.get(), F_SETPIPE_SZ, 0x7fffffffffffffff),
   620                SyscallFailsWithErrno(EINVAL));
   621  }
   622  
   623  TEST_P(PipeTest, SizeChangeFull) {
   624    SKIP_IF(!CreateBlocking());
   625  
   626    // Ensure that we adjust to a large enough size to avoid rounding when we
   627    // perform the size decrease. If rounding occurs, we may not actually
   628    // adjust the size and the call below will return success. It was found via
   629    // experimentation that this granularity avoids the rounding for Linux.
   630    constexpr int kDelta = 64 * 1024;
   631    ASSERT_THAT(fcntl(wfd_.get(), F_SETPIPE_SZ, Size() + kDelta),
   632                SyscallSucceeds());
   633  
   634    // Fill the buffer and try to change down.
   635    std::vector<char> buf(Size());
   636    ASSERT_THAT(write(wfd_.get(), buf.data(), buf.size()),
   637                SyscallSucceedsWithValue(buf.size()));
   638    EXPECT_THAT(fcntl(wfd_.get(), F_SETPIPE_SZ, Size() - kDelta),
   639                SyscallFailsWithErrno(EBUSY));
   640  }
   641  
   642  TEST_P(PipeTest, Streaming) {
   643    SKIP_IF(!CreateBlocking());
   644  
   645    // We make too many calls to go through full save cycles.
   646    DisableSave ds;
   647  
   648    // Size() requires 2 syscalls, call it once and remember the value.
   649    const size_t pipe_size = Size();
   650    const size_t streamed_bytes = 4 * pipe_size;
   651  
   652    absl::Notification notify;
   653    ScopedThread t([&, this]() {
   654      std::vector<char> buf(1024);
   655      // Don't start until it's full.
   656      notify.WaitForNotification();
   657      size_t total = 0;
   658      while (total < streamed_bytes) {
   659        ASSERT_THAT(read(rfd_.get(), buf.data(), buf.size()),
   660                    SyscallSucceedsWithValue(buf.size()));
   661        total += buf.size();
   662      }
   663    });
   664  
   665    // Write 4 bytes * pipe_size. It will fill up the pipe once, notify the reader
   666    // to start. Then we write pipe size worth 3 more times to ensure the reader
   667    // can follow along.
   668    //
   669    // The size of each write (which is determined by buf.size()) must be smaller
   670    // than the size of the pipe (which, in the "smallbuffer" configuration, is 1
   671    // page) for the check for notify.Notify() below to be correct.
   672    std::vector<char> buf(1024);
   673    RandomizeBuffer(buf.data(), buf.size());
   674    size_t total = 0;
   675    while (total < streamed_bytes) {
   676      ASSERT_THAT(write(wfd_.get(), buf.data(), buf.size()),
   677                  SyscallSucceedsWithValue(buf.size()));
   678      total += buf.size();
   679  
   680      // Is the next write about to fill up the buffer? Wake up the reader once.
   681      if (total < pipe_size && (total + buf.size()) >= pipe_size) {
   682        notify.Notify();
   683      }
   684    }
   685  }
   686  
   687  TEST_P(PipeTest, ZeroSize) {
   688    SKIP_IF(!CreateBlocking());
   689  
   690    ASSERT_THAT(write(wfd_.get(), nullptr, 0), SyscallSucceedsWithValue(0));
   691    ASSERT_THAT(read(rfd_.get(), nullptr, 0), SyscallSucceedsWithValue(0));
   692  }
   693  
   694  std::string PipeCreatorName(::testing::TestParamInfo<PipeCreator> info) {
   695    return info.param.name_;  // Use the name specified.
   696  }
   697  
   698  INSTANTIATE_TEST_SUITE_P(
   699      Pipes, PipeTest,
   700      ::testing::Values(
   701          PipeCreator{
   702              "pipe",
   703              [](int fds[2], bool* is_blocking, bool* is_namedpipe) {
   704                ASSERT_THAT(pipe(fds), SyscallSucceeds());
   705                *is_blocking = true;
   706                *is_namedpipe = false;
   707              },
   708          },
   709          PipeCreator{
   710              "pipe2blocking",
   711              [](int fds[2], bool* is_blocking, bool* is_namedpipe) {
   712                ASSERT_THAT(pipe2(fds, 0), SyscallSucceeds());
   713                *is_blocking = true;
   714                *is_namedpipe = false;
   715              },
   716          },
   717          PipeCreator{
   718              "pipe2nonblocking",
   719              [](int fds[2], bool* is_blocking, bool* is_namedpipe) {
   720                ASSERT_THAT(pipe2(fds, O_NONBLOCK), SyscallSucceeds());
   721                *is_blocking = false;
   722                *is_namedpipe = false;
   723              },
   724          },
   725          PipeCreator{
   726              "smallbuffer",
   727              [](int fds[2], bool* is_blocking, bool* is_namedpipe) {
   728                // Set to the minimum available size (will round up).
   729                ASSERT_THAT(pipe(fds), SyscallSucceeds());
   730                ASSERT_THAT(fcntl(fds[0], F_SETPIPE_SZ, 0), SyscallSucceeds());
   731                *is_blocking = true;
   732                *is_namedpipe = false;
   733              },
   734          },
   735          PipeCreator{
   736              "namednonblocking",
   737              [](int fds[2], bool* is_blocking, bool* is_namedpipe) {
   738                // Create a new file-based pipe (non-blocking).
   739                std::string path;
   740                {
   741                  auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   742                  path = file.path();
   743                }
   744                SKIP_IF(mkfifo(path.c_str(), 0644) != 0);
   745                fds[0] = open(path.c_str(), O_NONBLOCK | O_RDONLY);
   746                fds[1] = open(path.c_str(), O_NONBLOCK | O_WRONLY);
   747                MaybeSave();
   748                *is_blocking = false;
   749                *is_namedpipe = true;
   750              },
   751          },
   752          PipeCreator{
   753              "namedblocking",
   754              [](int fds[2], bool* is_blocking, bool* is_namedpipe) {
   755                // Create a new file-based pipe (blocking).
   756                std::string path;
   757                {
   758                  auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   759                  path = file.path();
   760                }
   761                SKIP_IF(mkfifo(path.c_str(), 0644) != 0);
   762                ScopedThread t(
   763                    [&path, &fds]() { fds[1] = open(path.c_str(), O_WRONLY); });
   764                fds[0] = open(path.c_str(), O_RDONLY);
   765                t.Join();
   766                MaybeSave();
   767                *is_blocking = true;
   768                *is_namedpipe = true;
   769              },
   770          }),
   771      PipeCreatorName);
   772  
   773  }  // namespace
   774  }  // namespace testing
   775  }  // namespace gvisor