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

     1  // Copyright 2019 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 <linux/unistd.h>
    17  #include <sys/eventfd.h>
    18  #include <sys/resource.h>
    19  #include <sys/sendfile.h>
    20  #include <sys/time.h>
    21  #include <unistd.h>
    22  
    23  #include "gmock/gmock.h"
    24  #include "gtest/gtest.h"
    25  #include "absl/cleanup/cleanup.h"
    26  #include "absl/strings/string_view.h"
    27  #include "absl/time/clock.h"
    28  #include "absl/time/time.h"
    29  #include "test/util/file_descriptor.h"
    30  #include "test/util/memory_util.h"
    31  #include "test/util/signal_util.h"
    32  #include "test/util/temp_path.h"
    33  #include "test/util/test_util.h"
    34  #include "test/util/thread_util.h"
    35  #include "test/util/timer_util.h"
    36  
    37  namespace gvisor {
    38  namespace testing {
    39  
    40  namespace {
    41  
    42  TEST(SpliceTest, TwoRegularFiles) {
    43    // Create temp files.
    44    const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    45    const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    46  
    47    // Open the input file as read only.
    48    const FileDescriptor in_fd =
    49        ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY));
    50  
    51    // Open the output file as write only.
    52    const FileDescriptor out_fd =
    53        ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_WRONLY));
    54  
    55    // Verify that it is rejected as expected; regardless of offsets.
    56    loff_t in_offset = 0;
    57    loff_t out_offset = 0;
    58    EXPECT_THAT(splice(in_fd.get(), &in_offset, out_fd.get(), &out_offset, 1, 0),
    59                SyscallFailsWithErrno(EINVAL));
    60    EXPECT_THAT(splice(in_fd.get(), nullptr, out_fd.get(), &out_offset, 1, 0),
    61                SyscallFailsWithErrno(EINVAL));
    62    EXPECT_THAT(splice(in_fd.get(), &in_offset, out_fd.get(), nullptr, 1, 0),
    63                SyscallFailsWithErrno(EINVAL));
    64    EXPECT_THAT(splice(in_fd.get(), nullptr, out_fd.get(), nullptr, 1, 0),
    65                SyscallFailsWithErrno(EINVAL));
    66  }
    67  
    68  int memfd_create(const std::string& name, unsigned int flags) {
    69    return syscall(__NR_memfd_create, name.c_str(), flags);
    70  }
    71  
    72  TEST(SpliceTest, NegativeOffset) {
    73    // Create a new pipe.
    74    int fds[2];
    75    ASSERT_THAT(pipe(fds), SyscallSucceeds());
    76    const FileDescriptor rfd(fds[0]);
    77    const FileDescriptor wfd(fds[1]);
    78  
    79    // Fill the pipe.
    80    std::vector<char> buf(kPageSize);
    81    RandomizeBuffer(buf.data(), buf.size());
    82    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
    83                SyscallSucceedsWithValue(kPageSize));
    84  
    85    // Open the output file as write only.
    86    int fd;
    87    EXPECT_THAT(fd = memfd_create("negative", 0), SyscallSucceeds());
    88    const FileDescriptor out_fd(fd);
    89  
    90    loff_t out_offset = 0xffffffffffffffffull;
    91    constexpr int kSize = 2;
    92    EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), &out_offset, kSize, 0),
    93                SyscallFailsWithErrno(EINVAL));
    94  }
    95  
    96  // Write offset + size overflows int64.
    97  //
    98  // This is a regression test for b/148041624.
    99  TEST(SpliceTest, WriteOverflow) {
   100    // Create a new pipe.
   101    int fds[2];
   102    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   103    const FileDescriptor rfd(fds[0]);
   104    const FileDescriptor wfd(fds[1]);
   105  
   106    // Fill the pipe.
   107    std::vector<char> buf(kPageSize);
   108    RandomizeBuffer(buf.data(), buf.size());
   109    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
   110                SyscallSucceedsWithValue(kPageSize));
   111  
   112    // Open the output file.
   113    int fd;
   114    EXPECT_THAT(fd = memfd_create("overflow", 0), SyscallSucceeds());
   115    const FileDescriptor out_fd(fd);
   116  
   117    // out_offset + kSize overflows INT64_MAX.
   118    loff_t out_offset = 0x7ffffffffffffffeull;
   119    constexpr int kSize = 3;
   120    EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), &out_offset, kSize, 0),
   121                SyscallFailsWithErrno(EINVAL));
   122  }
   123  
   124  TEST(SpliceTest, SamePipe) {
   125    // Create a new pipe.
   126    int fds[2];
   127    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   128    const FileDescriptor rfd(fds[0]);
   129    const FileDescriptor wfd(fds[1]);
   130  
   131    // Fill the pipe.
   132    std::vector<char> buf(kPageSize);
   133    RandomizeBuffer(buf.data(), buf.size());
   134    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
   135                SyscallSucceedsWithValue(kPageSize));
   136  
   137    // Attempt to splice to itself.
   138    EXPECT_THAT(splice(rfd.get(), nullptr, wfd.get(), nullptr, kPageSize, 0),
   139                SyscallFailsWithErrno(EINVAL));
   140  }
   141  
   142  TEST(TeeTest, SamePipe) {
   143    // Create a new pipe.
   144    int fds[2];
   145    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   146    const FileDescriptor rfd(fds[0]);
   147    const FileDescriptor wfd(fds[1]);
   148  
   149    // Fill the pipe.
   150    std::vector<char> buf(kPageSize);
   151    RandomizeBuffer(buf.data(), buf.size());
   152    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
   153                SyscallSucceedsWithValue(kPageSize));
   154  
   155    // Attempt to tee to itself.
   156    EXPECT_THAT(tee(rfd.get(), wfd.get(), kPageSize, 0),
   157                SyscallFailsWithErrno(EINVAL));
   158  }
   159  
   160  TEST(TeeTest, RegularFile) {
   161    // Open some file.
   162    const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   163    const FileDescriptor in_fd =
   164        ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDWR));
   165  
   166    // Create a new pipe.
   167    int fds[2];
   168    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   169    const FileDescriptor rfd(fds[0]);
   170    const FileDescriptor wfd(fds[1]);
   171  
   172    // Attempt to tee from the file.
   173    EXPECT_THAT(tee(in_fd.get(), wfd.get(), kPageSize, 0),
   174                SyscallFailsWithErrno(EINVAL));
   175    EXPECT_THAT(tee(rfd.get(), in_fd.get(), kPageSize, 0),
   176                SyscallFailsWithErrno(EINVAL));
   177  }
   178  
   179  TEST(SpliceTest, PipeOffsets) {
   180    // Create two new pipes.
   181    int first[2], second[2];
   182    ASSERT_THAT(pipe(first), SyscallSucceeds());
   183    const FileDescriptor rfd1(first[0]);
   184    const FileDescriptor wfd1(first[1]);
   185    ASSERT_THAT(pipe(second), SyscallSucceeds());
   186    const FileDescriptor rfd2(second[0]);
   187    const FileDescriptor wfd2(second[1]);
   188  
   189    // All pipe offsets should be rejected.
   190    loff_t in_offset = 0;
   191    loff_t out_offset = 0;
   192    EXPECT_THAT(splice(rfd1.get(), &in_offset, wfd2.get(), &out_offset, 1, 0),
   193                SyscallFailsWithErrno(ESPIPE));
   194    EXPECT_THAT(splice(rfd1.get(), nullptr, wfd2.get(), &out_offset, 1, 0),
   195                SyscallFailsWithErrno(ESPIPE));
   196    EXPECT_THAT(splice(rfd1.get(), &in_offset, wfd2.get(), nullptr, 1, 0),
   197                SyscallFailsWithErrno(ESPIPE));
   198  }
   199  
   200  TEST(SpliceTest, ToPipe) {
   201    // Open the input file.
   202    const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   203    const FileDescriptor in_fd =
   204        ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDWR));
   205  
   206    // Fill with some random data.
   207    std::vector<char> buf(kPageSize);
   208    RandomizeBuffer(buf.data(), buf.size());
   209    ASSERT_THAT(write(in_fd.get(), buf.data(), buf.size()),
   210                SyscallSucceedsWithValue(kPageSize));
   211    ASSERT_THAT(lseek(in_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0));
   212  
   213    // Create a new pipe.
   214    int fds[2];
   215    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   216    const FileDescriptor rfd(fds[0]);
   217    const FileDescriptor wfd(fds[1]);
   218  
   219    // Splice to the pipe.
   220    EXPECT_THAT(splice(in_fd.get(), nullptr, wfd.get(), nullptr, kPageSize, 0),
   221                SyscallSucceedsWithValue(kPageSize));
   222  
   223    // Contents should be equal.
   224    std::vector<char> rbuf(kPageSize);
   225    ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()),
   226                SyscallSucceedsWithValue(kPageSize));
   227    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0);
   228  }
   229  
   230  TEST(SpliceTest, ToPipeEOF) {
   231    // Create and open an empty input file.
   232    const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   233    const FileDescriptor in_fd =
   234        ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY));
   235  
   236    // Create a new pipe.
   237    int fds[2];
   238    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   239    const FileDescriptor rfd(fds[0]);
   240    const FileDescriptor wfd(fds[1]);
   241  
   242    // Splice from the empty file to the pipe.
   243    EXPECT_THAT(splice(in_fd.get(), nullptr, wfd.get(), nullptr, 123, 0),
   244                SyscallSucceedsWithValue(0));
   245  }
   246  
   247  TEST(SpliceTest, ToPipeOffset) {
   248    // Open the input file.
   249    const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   250    const FileDescriptor in_fd =
   251        ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDWR));
   252  
   253    // Fill with some random data.
   254    std::vector<char> buf(kPageSize);
   255    RandomizeBuffer(buf.data(), buf.size());
   256    ASSERT_THAT(write(in_fd.get(), buf.data(), buf.size()),
   257                SyscallSucceedsWithValue(kPageSize));
   258  
   259    // Create a new pipe.
   260    int fds[2];
   261    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   262    const FileDescriptor rfd(fds[0]);
   263    const FileDescriptor wfd(fds[1]);
   264  
   265    // Splice to the pipe.
   266    loff_t in_offset = kPageSize / 2;
   267    EXPECT_THAT(
   268        splice(in_fd.get(), &in_offset, wfd.get(), nullptr, kPageSize / 2, 0),
   269        SyscallSucceedsWithValue(kPageSize / 2));
   270  
   271    // Contents should be equal to only the second part.
   272    std::vector<char> rbuf(kPageSize / 2);
   273    ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()),
   274                SyscallSucceedsWithValue(kPageSize / 2));
   275    EXPECT_EQ(memcmp(rbuf.data(), buf.data() + (kPageSize / 2), rbuf.size()), 0);
   276  }
   277  
   278  TEST(SpliceTest, FromPipe) {
   279    // Create a new pipe.
   280    int fds[2];
   281    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   282    const FileDescriptor rfd(fds[0]);
   283    const FileDescriptor wfd(fds[1]);
   284  
   285    // Fill with some random data.
   286    std::vector<char> buf(kPageSize);
   287    RandomizeBuffer(buf.data(), buf.size());
   288    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
   289                SyscallSucceedsWithValue(kPageSize));
   290  
   291    // Open the output file.
   292    const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   293    const FileDescriptor out_fd =
   294        ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR));
   295  
   296    // Splice to the output file.
   297    EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, kPageSize, 0),
   298                SyscallSucceedsWithValue(kPageSize));
   299  
   300    // The offset of the output should be equal to kPageSize. We assert that and
   301    // reset to zero so that we can read the contents and ensure they match.
   302    EXPECT_THAT(lseek(out_fd.get(), 0, SEEK_CUR),
   303                SyscallSucceedsWithValue(kPageSize));
   304    ASSERT_THAT(lseek(out_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0));
   305  
   306    // Contents should be equal.
   307    std::vector<char> rbuf(kPageSize);
   308    ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()),
   309                SyscallSucceedsWithValue(kPageSize));
   310    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0);
   311  }
   312  
   313  TEST(SpliceTest, FromPipeMultiple) {
   314    // Create a new pipe.
   315    int fds[2];
   316    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   317    const FileDescriptor rfd(fds[0]);
   318    const FileDescriptor wfd(fds[1]);
   319  
   320    std::string buf = "abcABC123";
   321    ASSERT_THAT(write(wfd.get(), buf.c_str(), buf.size()),
   322                SyscallSucceedsWithValue(buf.size()));
   323  
   324    // Open the output file.
   325    const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   326    const FileDescriptor out_fd =
   327        ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR));
   328  
   329    // Splice from the pipe to the output file over several calls.
   330    EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0),
   331                SyscallSucceedsWithValue(3));
   332    EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0),
   333                SyscallSucceedsWithValue(3));
   334    EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0),
   335                SyscallSucceedsWithValue(3));
   336  
   337    // Reset cursor to zero so that we can check the contents.
   338    ASSERT_THAT(lseek(out_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0));
   339  
   340    // Contents should be equal.
   341    std::vector<char> rbuf(buf.size());
   342    ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()),
   343                SyscallSucceedsWithValue(rbuf.size()));
   344    EXPECT_EQ(memcmp(rbuf.data(), buf.c_str(), buf.size()), 0);
   345  }
   346  
   347  TEST(SpliceTest, FromPipeOffset) {
   348    // Create a new pipe.
   349    int fds[2];
   350    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   351    const FileDescriptor rfd(fds[0]);
   352    const FileDescriptor wfd(fds[1]);
   353  
   354    // Fill with some random data.
   355    std::vector<char> buf(kPageSize);
   356    RandomizeBuffer(buf.data(), buf.size());
   357    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
   358                SyscallSucceedsWithValue(kPageSize));
   359  
   360    // Open the input file.
   361    const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   362    const FileDescriptor out_fd =
   363        ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR));
   364  
   365    // Splice to the output file.
   366    loff_t out_offset = kPageSize / 2;
   367    EXPECT_THAT(
   368        splice(rfd.get(), nullptr, out_fd.get(), &out_offset, kPageSize, 0),
   369        SyscallSucceedsWithValue(kPageSize));
   370  
   371    // Content should reflect the splice. We write to a specific offset in the
   372    // file, so the internals should now be allocated sparsely.
   373    std::vector<char> rbuf(kPageSize);
   374    ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()),
   375                SyscallSucceedsWithValue(kPageSize));
   376    std::vector<char> zbuf(kPageSize / 2);
   377    memset(zbuf.data(), 0, zbuf.size());
   378    EXPECT_EQ(memcmp(rbuf.data(), zbuf.data(), zbuf.size()), 0);
   379    EXPECT_EQ(memcmp(rbuf.data() + kPageSize / 2, buf.data(), kPageSize / 2), 0);
   380  }
   381  
   382  TEST(SpliceTest, TwoPipes) {
   383    // Create two new pipes.
   384    int first[2], second[2];
   385    ASSERT_THAT(pipe(first), SyscallSucceeds());
   386    const FileDescriptor rfd1(first[0]);
   387    const FileDescriptor wfd1(first[1]);
   388    ASSERT_THAT(pipe(second), SyscallSucceeds());
   389    const FileDescriptor rfd2(second[0]);
   390    const FileDescriptor wfd2(second[1]);
   391  
   392    // Fill with some random data.
   393    std::vector<char> buf(kPageSize);
   394    RandomizeBuffer(buf.data(), buf.size());
   395    ASSERT_THAT(write(wfd1.get(), buf.data(), buf.size()),
   396                SyscallSucceedsWithValue(kPageSize));
   397  
   398    // Splice to the second pipe, using two operations.
   399    EXPECT_THAT(
   400        splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize / 2, 0),
   401        SyscallSucceedsWithValue(kPageSize / 2));
   402    EXPECT_THAT(
   403        splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize / 2, 0),
   404        SyscallSucceedsWithValue(kPageSize / 2));
   405  
   406    // Content should reflect the splice.
   407    std::vector<char> rbuf(kPageSize);
   408    ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()),
   409                SyscallSucceedsWithValue(kPageSize));
   410    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0);
   411  }
   412  
   413  TEST(SpliceTest, TwoPipesPartialRead) {
   414    // Create two pipes.
   415    int fds[2];
   416    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   417    const FileDescriptor first_rfd(fds[0]);
   418    const FileDescriptor first_wfd(fds[1]);
   419    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   420    const FileDescriptor second_rfd(fds[0]);
   421    const FileDescriptor second_wfd(fds[1]);
   422  
   423    // Write half a page of data to the first pipe.
   424    std::vector<char> buf(kPageSize / 2);
   425    RandomizeBuffer(buf.data(), buf.size());
   426    ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()),
   427                SyscallSucceedsWithValue(kPageSize / 2));
   428  
   429    // Attempt to splice one page from the first pipe to the second; it should
   430    // immediately return after splicing the half-page previously written to the
   431    // first pipe.
   432    EXPECT_THAT(
   433        splice(first_rfd.get(), nullptr, second_wfd.get(), nullptr, kPageSize, 0),
   434        SyscallSucceedsWithValue(kPageSize / 2));
   435  }
   436  
   437  TEST(SpliceTest, TwoPipesPartialWrite) {
   438    // Create two pipes.
   439    int fds[2];
   440    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   441    const FileDescriptor first_rfd(fds[0]);
   442    const FileDescriptor first_wfd(fds[1]);
   443    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   444    const FileDescriptor second_rfd(fds[0]);
   445    const FileDescriptor second_wfd(fds[1]);
   446  
   447    // Write two pages of data to the first pipe.
   448    std::vector<char> buf(2 * kPageSize);
   449    RandomizeBuffer(buf.data(), buf.size());
   450    ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()),
   451                SyscallSucceedsWithValue(2 * kPageSize));
   452  
   453    // Limit the second pipe to two pages, then write one page of data to it.
   454    ASSERT_THAT(fcntl(second_wfd.get(), F_SETPIPE_SZ, 2 * kPageSize),
   455                SyscallSucceeds());
   456    ASSERT_THAT(write(second_wfd.get(), buf.data(), buf.size() / 2),
   457                SyscallSucceedsWithValue(kPageSize));
   458  
   459    // Attempt to splice two pages from the first pipe to the second; it should
   460    // immediately return after splicing the first page previously written to the
   461    // first pipe.
   462    EXPECT_THAT(splice(first_rfd.get(), nullptr, second_wfd.get(), nullptr,
   463                       2 * kPageSize, 0),
   464                SyscallSucceedsWithValue(kPageSize));
   465  }
   466  
   467  TEST(TeeTest, TwoPipesPartialRead) {
   468    // Create two pipes.
   469    int fds[2];
   470    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   471    const FileDescriptor first_rfd(fds[0]);
   472    const FileDescriptor first_wfd(fds[1]);
   473    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   474    const FileDescriptor second_rfd(fds[0]);
   475    const FileDescriptor second_wfd(fds[1]);
   476  
   477    // Write half a page of data to the first pipe.
   478    std::vector<char> buf(kPageSize / 2);
   479    RandomizeBuffer(buf.data(), buf.size());
   480    ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()),
   481                SyscallSucceedsWithValue(kPageSize / 2));
   482  
   483    // Attempt to tee one page from the first pipe to the second; it should
   484    // immediately return after copying the half-page previously written to the
   485    // first pipe.
   486    EXPECT_THAT(tee(first_rfd.get(), second_wfd.get(), kPageSize, 0),
   487                SyscallSucceedsWithValue(kPageSize / 2));
   488  }
   489  
   490  TEST(TeeTest, TwoPipesPartialWrite) {
   491    // Create two pipes.
   492    int fds[2];
   493    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   494    const FileDescriptor first_rfd(fds[0]);
   495    const FileDescriptor first_wfd(fds[1]);
   496    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   497    const FileDescriptor second_rfd(fds[0]);
   498    const FileDescriptor second_wfd(fds[1]);
   499  
   500    // Write two pages of data to the first pipe.
   501    std::vector<char> buf(2 * kPageSize);
   502    RandomizeBuffer(buf.data(), buf.size());
   503    ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()),
   504                SyscallSucceedsWithValue(2 * kPageSize));
   505  
   506    // Limit the second pipe to two pages, then write one page of data to it.
   507    ASSERT_THAT(fcntl(second_wfd.get(), F_SETPIPE_SZ, 2 * kPageSize),
   508                SyscallSucceeds());
   509    ASSERT_THAT(write(second_wfd.get(), buf.data(), buf.size() / 2),
   510                SyscallSucceedsWithValue(kPageSize));
   511  
   512    // Attempt to tee two pages from the first pipe to the second; it should
   513    // immediately return after copying the first page previously written to the
   514    // first pipe.
   515    EXPECT_THAT(tee(first_rfd.get(), second_wfd.get(), 2 * kPageSize, 0),
   516                SyscallSucceedsWithValue(kPageSize));
   517  }
   518  
   519  TEST(SpliceTest, TwoPipesCircular) {
   520    // Create two pipes.
   521    int fds[2];
   522    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   523    const FileDescriptor first_rfd(fds[0]);
   524    const FileDescriptor first_wfd(fds[1]);
   525    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   526    const FileDescriptor second_rfd(fds[0]);
   527    const FileDescriptor second_wfd(fds[1]);
   528  
   529    // On Linux, each pipe is normally limited to
   530    // include/linux/pipe_fs_i.h:PIPE_DEF_BUFFERS buffers worth of data.
   531    constexpr size_t PIPE_DEF_BUFFERS = 16;
   532  
   533    // Write some data to each pipe. Below we splice 1 byte at a time between
   534    // pipes, which very quickly causes each byte to be stored in a separate
   535    // buffer, so we must ensure that the total amount of data in the system is <=
   536    // PIPE_DEF_BUFFERS bytes.
   537    std::vector<char> buf(PIPE_DEF_BUFFERS / 2);
   538    RandomizeBuffer(buf.data(), buf.size());
   539    ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()),
   540                SyscallSucceedsWithValue(buf.size()));
   541    ASSERT_THAT(write(second_wfd.get(), buf.data(), buf.size()),
   542                SyscallSucceedsWithValue(buf.size()));
   543  
   544    // Have another thread splice from the second pipe to the first, while we
   545    // splice from the first to the second. The test passes if this does not
   546    // deadlock.
   547    const int kIterations = 1000;
   548    DisableSave ds;
   549    ScopedThread t([&]() {
   550      for (int i = 0; i < kIterations; i++) {
   551        ASSERT_THAT(
   552            splice(second_rfd.get(), nullptr, first_wfd.get(), nullptr, 1, 0),
   553            SyscallSucceedsWithValue(1));
   554      }
   555    });
   556    for (int i = 0; i < kIterations; i++) {
   557      ASSERT_THAT(
   558          splice(first_rfd.get(), nullptr, second_wfd.get(), nullptr, 1, 0),
   559          SyscallSucceedsWithValue(1));
   560    }
   561  }
   562  
   563  TEST(SpliceTest, Blocking) {
   564    // Create two new pipes.
   565    int first[2], second[2];
   566    ASSERT_THAT(pipe(first), SyscallSucceeds());
   567    const FileDescriptor rfd1(first[0]);
   568    const FileDescriptor wfd1(first[1]);
   569    ASSERT_THAT(pipe(second), SyscallSucceeds());
   570    const FileDescriptor rfd2(second[0]);
   571    const FileDescriptor wfd2(second[1]);
   572  
   573    // This thread writes to the main pipe.
   574    std::vector<char> buf(kPageSize);
   575    RandomizeBuffer(buf.data(), buf.size());
   576    ScopedThread t([&]() {
   577      ASSERT_THAT(write(wfd1.get(), buf.data(), buf.size()),
   578                  SyscallSucceedsWithValue(kPageSize));
   579    });
   580  
   581    // Attempt a splice immediately; it should block.
   582    EXPECT_THAT(splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize, 0),
   583                SyscallSucceedsWithValue(kPageSize));
   584  
   585    // Thread should be joinable.
   586    t.Join();
   587  
   588    // Content should reflect the splice.
   589    std::vector<char> rbuf(kPageSize);
   590    ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()),
   591                SyscallSucceedsWithValue(kPageSize));
   592    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0);
   593  }
   594  
   595  TEST(TeeTest, Blocking) {
   596    // Create two new pipes.
   597    int first[2], second[2];
   598    ASSERT_THAT(pipe(first), SyscallSucceeds());
   599    const FileDescriptor rfd1(first[0]);
   600    const FileDescriptor wfd1(first[1]);
   601    ASSERT_THAT(pipe(second), SyscallSucceeds());
   602    const FileDescriptor rfd2(second[0]);
   603    const FileDescriptor wfd2(second[1]);
   604  
   605    // This thread writes to the main pipe.
   606    std::vector<char> buf(kPageSize);
   607    RandomizeBuffer(buf.data(), buf.size());
   608    ScopedThread t([&]() {
   609      ASSERT_THAT(write(wfd1.get(), buf.data(), buf.size()),
   610                  SyscallSucceedsWithValue(kPageSize));
   611    });
   612  
   613    // Attempt a tee immediately; it should block.
   614    EXPECT_THAT(tee(rfd1.get(), wfd2.get(), kPageSize, 0),
   615                SyscallSucceedsWithValue(kPageSize));
   616  
   617    // Thread should be joinable.
   618    t.Join();
   619  
   620    // Content should reflect the splice, in both pipes.
   621    std::vector<char> rbuf(kPageSize);
   622    ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()),
   623                SyscallSucceedsWithValue(kPageSize));
   624    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0);
   625    ASSERT_THAT(read(rfd1.get(), rbuf.data(), rbuf.size()),
   626                SyscallSucceedsWithValue(kPageSize));
   627    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0);
   628  }
   629  
   630  TEST(TeeTest, BlockingWrite) {
   631    // Create two new pipes.
   632    int first[2], second[2];
   633    ASSERT_THAT(pipe(first), SyscallSucceeds());
   634    const FileDescriptor rfd1(first[0]);
   635    const FileDescriptor wfd1(first[1]);
   636    ASSERT_THAT(pipe(second), SyscallSucceeds());
   637    const FileDescriptor rfd2(second[0]);
   638    const FileDescriptor wfd2(second[1]);
   639  
   640    // Make some data available to be read.
   641    std::vector<char> buf1(kPageSize);
   642    RandomizeBuffer(buf1.data(), buf1.size());
   643    ASSERT_THAT(write(wfd1.get(), buf1.data(), buf1.size()),
   644                SyscallSucceedsWithValue(kPageSize));
   645  
   646    // Fill up the write pipe's buffer.
   647    int pipe_size = -1;
   648    ASSERT_THAT(pipe_size = fcntl(wfd2.get(), F_GETPIPE_SZ), SyscallSucceeds());
   649    std::vector<char> buf2(pipe_size);
   650    ASSERT_THAT(write(wfd2.get(), buf2.data(), buf2.size()),
   651                SyscallSucceedsWithValue(pipe_size));
   652  
   653    ScopedThread t([&]() {
   654      absl::SleepFor(absl::Milliseconds(100));
   655      ASSERT_THAT(read(rfd2.get(), buf2.data(), buf2.size()),
   656                  SyscallSucceedsWithValue(pipe_size));
   657    });
   658  
   659    // Attempt a tee immediately; it should block.
   660    EXPECT_THAT(tee(rfd1.get(), wfd2.get(), kPageSize, 0),
   661                SyscallSucceedsWithValue(kPageSize));
   662  
   663    // Thread should be joinable.
   664    t.Join();
   665  
   666    // Content should reflect the tee.
   667    std::vector<char> rbuf(kPageSize);
   668    ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()),
   669                SyscallSucceedsWithValue(kPageSize));
   670    EXPECT_EQ(memcmp(rbuf.data(), buf1.data(), kPageSize), 0);
   671  }
   672  
   673  TEST(SpliceTest, NonBlocking) {
   674    // Create two new pipes.
   675    int first[2], second[2];
   676    ASSERT_THAT(pipe(first), SyscallSucceeds());
   677    const FileDescriptor rfd1(first[0]);
   678    const FileDescriptor wfd1(first[1]);
   679    ASSERT_THAT(pipe(second), SyscallSucceeds());
   680    const FileDescriptor rfd2(second[0]);
   681    const FileDescriptor wfd2(second[1]);
   682  
   683    // Splice with no data to back it.
   684    EXPECT_THAT(splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize,
   685                       SPLICE_F_NONBLOCK),
   686                SyscallFailsWithErrno(EAGAIN));
   687  }
   688  
   689  TEST(TeeTest, NonBlocking) {
   690    // Create two new pipes.
   691    int first[2], second[2];
   692    ASSERT_THAT(pipe(first), SyscallSucceeds());
   693    const FileDescriptor rfd1(first[0]);
   694    const FileDescriptor wfd1(first[1]);
   695    ASSERT_THAT(pipe(second), SyscallSucceeds());
   696    const FileDescriptor rfd2(second[0]);
   697    const FileDescriptor wfd2(second[1]);
   698  
   699    // Splice with no data to back it.
   700    EXPECT_THAT(tee(rfd1.get(), wfd2.get(), kPageSize, SPLICE_F_NONBLOCK),
   701                SyscallFailsWithErrno(EAGAIN));
   702  }
   703  
   704  TEST(TeeTest, MultiPage) {
   705    // Create two new pipes.
   706    int first[2], second[2];
   707    ASSERT_THAT(pipe(first), SyscallSucceeds());
   708    const FileDescriptor rfd1(first[0]);
   709    const FileDescriptor wfd1(first[1]);
   710    ASSERT_THAT(pipe(second), SyscallSucceeds());
   711    const FileDescriptor rfd2(second[0]);
   712    const FileDescriptor wfd2(second[1]);
   713  
   714    // Make some data available to be read.
   715    std::vector<char> wbuf(8 * kPageSize);
   716    RandomizeBuffer(wbuf.data(), wbuf.size());
   717    ASSERT_THAT(write(wfd1.get(), wbuf.data(), wbuf.size()),
   718                SyscallSucceedsWithValue(wbuf.size()));
   719  
   720    // Attempt a tee immediately; it should complete.
   721    EXPECT_THAT(tee(rfd1.get(), wfd2.get(), wbuf.size(), 0),
   722                SyscallSucceedsWithValue(wbuf.size()));
   723  
   724    // Content should reflect the tee.
   725    std::vector<char> rbuf(wbuf.size());
   726    ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()),
   727                SyscallSucceedsWithValue(rbuf.size()));
   728    EXPECT_EQ(memcmp(rbuf.data(), wbuf.data(), rbuf.size()), 0);
   729    ASSERT_THAT(read(rfd1.get(), rbuf.data(), rbuf.size()),
   730                SyscallSucceedsWithValue(rbuf.size()));
   731    EXPECT_EQ(memcmp(rbuf.data(), wbuf.data(), rbuf.size()), 0);
   732  }
   733  
   734  TEST(SpliceTest, FromPipeMaxFileSize) {
   735    // Create a new pipe.
   736    int fds[2];
   737    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   738    const FileDescriptor rfd(fds[0]);
   739    const FileDescriptor wfd(fds[1]);
   740  
   741    // Fill with some random data.
   742    std::vector<char> buf(kPageSize);
   743    RandomizeBuffer(buf.data(), buf.size());
   744    ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
   745                SyscallSucceedsWithValue(kPageSize));
   746  
   747    // Open the input file.
   748    const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   749    const FileDescriptor out_fd =
   750        ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR));
   751  
   752    EXPECT_THAT(ftruncate(out_fd.get(), 13 << 20), SyscallSucceeds());
   753    EXPECT_THAT(lseek(out_fd.get(), 0, SEEK_END),
   754                SyscallSucceedsWithValue(13 << 20));
   755  
   756    // Set our file size limit.
   757    sigset_t set;
   758    sigemptyset(&set);
   759    sigaddset(&set, SIGXFSZ);
   760    TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0);
   761    rlimit rlim = {};
   762    rlim.rlim_cur = rlim.rlim_max = (13 << 20);
   763    EXPECT_THAT(setrlimit(RLIMIT_FSIZE, &rlim), SyscallSucceeds());
   764  
   765    // Splice to the output file.
   766    EXPECT_THAT(
   767        splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3 * kPageSize, 0),
   768        SyscallFailsWithErrno(EFBIG));
   769  
   770    // Contents should be equal.
   771    std::vector<char> rbuf(kPageSize);
   772    ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()),
   773                SyscallSucceedsWithValue(kPageSize));
   774    EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0);
   775  }
   776  
   777  static volatile int signaled = 0;
   778  void SigUsr1Handler(int sig, siginfo_t* info, void* context) { signaled = 1; }
   779  
   780  TEST(SpliceTest, ToPipeWithSmallCapacityDoesNotSpin) {
   781    // Writes to a pipe that are less than PIPE_BUF must be atomic. This test
   782    // creates a pipe with only 128 bytes of capacity (< PIPE_BUF) and checks that
   783    // splicing to the pipe does not spin. See b/170743336.
   784  
   785    // Create a file with one page of data.
   786    std::vector<char> buf(kPageSize);
   787    RandomizeBuffer(buf.data(), buf.size());
   788    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   789        GetAbsoluteTestTmpdir(), absl::string_view(buf.data(), buf.size()),
   790        TempPath::kDefaultFileMode));
   791    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY));
   792  
   793    // Create a pipe with size 4096, and fill all but 128 bytes of it.
   794    int p[2];
   795    ASSERT_THAT(pipe(p), SyscallSucceeds());
   796    ASSERT_THAT(fcntl(p[1], F_SETPIPE_SZ, kPageSize), SyscallSucceeds());
   797    const int kWriteSize = kPageSize - 128;
   798    std::vector<char> writeBuf(kWriteSize);
   799    RandomizeBuffer(writeBuf.data(), writeBuf.size());
   800    ASSERT_THAT(write(p[1], writeBuf.data(), writeBuf.size()),
   801                SyscallSucceedsWithValue(kWriteSize));
   802  
   803    // Set up signal handler.
   804    struct sigaction sa = {};
   805    sa.sa_sigaction = SigUsr1Handler;
   806    sa.sa_flags = SA_SIGINFO;
   807    const auto cleanup_sigact =
   808        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGUSR1, sa));
   809  
   810    // Send SIGUSR1 to this thread in 1 second.
   811    struct sigevent sev = {};
   812    sev.sigev_notify = SIGEV_THREAD_ID;
   813    sev.sigev_signo = SIGUSR1;
   814    sev.sigev_notify_thread_id = gettid();
   815    auto timer = ASSERT_NO_ERRNO_AND_VALUE(TimerCreate(CLOCK_MONOTONIC, sev));
   816    struct itimerspec its = {};
   817    its.it_value = absl::ToTimespec(absl::Seconds(1));
   818    DisableSave ds;  // Asserting an EINTR.
   819    ASSERT_NO_ERRNO(timer.Set(0, its));
   820  
   821    // Now splice the file to the pipe. This should block, but not spin, and
   822    // should return EINTR because it is interrupted by the signal.
   823    EXPECT_THAT(splice(fd.get(), nullptr, p[1], nullptr, kPageSize, 0),
   824                SyscallFailsWithErrno(EINTR));
   825  
   826    // Alarm should have been handled.
   827    EXPECT_EQ(signaled, 1);
   828  }
   829  
   830  // Regression test for b/208679047.
   831  TEST(SpliceTest, FromPipeWithConcurrentIo) {
   832    // Create a file containing two copies of the same byte. Two bytes are
   833    // necessary because both the read() and splice() loops below advance the file
   834    // offset by one byte before lseek(); use of the file offset is required since
   835    // the mutex protecting the file offset is implicated in the circular lock
   836    // ordering that this test attempts to reproduce.
   837    //
   838    // This can't use memfd_create() because, in Linux, memfd_create(2) creates a
   839    // struct file using alloc_file_pseudo() without going through
   840    // do_dentry_open(), so FMODE_ATOMIC_POS is not set despite the created file
   841    // having type S_IFREG ("regular file").
   842    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   843    const FileDescriptor fd =
   844        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
   845    constexpr char kSplicedByte = 0x01;
   846    for (int i = 0; i < 2; i++) {
   847      ASSERT_THAT(WriteFd(fd.get(), &kSplicedByte, 1),
   848                  SyscallSucceedsWithValue(1));
   849    }
   850  
   851    // Create a pipe.
   852    int pipe_fds[2];
   853    ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds());
   854    const FileDescriptor rfd(pipe_fds[0]);
   855    FileDescriptor wfd(pipe_fds[1]);
   856  
   857    DisableSave ds;
   858    std::atomic<bool> done(false);
   859  
   860    // Create a thread that reads from fd until the end of the test.
   861    ScopedThread memfd_reader([&] {
   862      char file_buf;
   863      while (!done.load()) {
   864        ASSERT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallSucceeds());
   865        int n = ReadFd(fd.get(), &file_buf, 1);
   866        if (n == 0) {
   867          // fd was at offset 2 (EOF). In Linux, this is possible even after
   868          // lseek(0) because splice() doesn't attempt atomicity with respect to
   869          // concurrent lseek(), so the effect of lseek() may be lost.
   870          continue;
   871        }
   872        ASSERT_THAT(n, SyscallSucceedsWithValue(1));
   873        ASSERT_EQ(file_buf, kSplicedByte);
   874      }
   875    });
   876  
   877    // Create a thread that reads from the pipe until the end of the test.
   878    ScopedThread pipe_reader([&] {
   879      char pipe_buf;
   880      while (!done.load()) {
   881        int n = ReadFd(rfd.get(), &pipe_buf, 1);
   882        if (n == 0) {
   883          // This should only happen due to cleanup_threads (below) closing wfd.
   884          EXPECT_TRUE(done.load());
   885          return;
   886        }
   887        ASSERT_THAT(n, SyscallSucceedsWithValue(1));
   888        ASSERT_EQ(pipe_buf, kSplicedByte);
   889      }
   890    });
   891  
   892    // Create a thread that repeatedly invokes madvise(MADV_DONTNEED) on the same
   893    // page of memory. (Having a thread attempt to lock MM.activeMu for writing is
   894    // necessary to create a deadlock from the circular lock ordering, since
   895    // otherwise both uses of MM.activeMu are for reading and may proceed
   896    // concurrently.)
   897    ScopedThread mm_locker([&] {
   898      const Mapping m = ASSERT_NO_ERRNO_AND_VALUE(
   899          MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE));
   900      while (!done.load()) {
   901        madvise(m.ptr(), kPageSize, MADV_DONTNEED);
   902      }
   903    });
   904  
   905    // This must come after the ScopedThreads since its destructor must run before
   906    // theirs.
   907    const absl::Cleanup cleanup_threads = [&] {
   908      done.store(true);
   909      // Ensure that pipe_reader is unblocked after setting done, so that it will
   910      // be able to observe done being true.
   911      wfd.reset();
   912    };
   913  
   914    // Repeatedly splice from memfd to the pipe. The test passes if this does not
   915    // deadlock.
   916    const int kIterations = 5000;
   917    for (int i = 0; i < kIterations; i++) {
   918      ASSERT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallSucceeds());
   919      ASSERT_THAT(splice(fd.get(), nullptr, wfd.get(), nullptr, 1, 0),
   920                  SyscallSucceedsWithValue(1));
   921    }
   922  }
   923  
   924  // Regression test for #9736 and #10046.
   925  TEST(SpliceTest, FromPipeWithWriterToDevNull) {
   926    int fds[2];
   927    ASSERT_THAT(pipe(fds), SyscallSucceeds());
   928    const FileDescriptor rfd(fds[0]);
   929    const FileDescriptor wfd(fds[1]);
   930    const FileDescriptor out_fd =
   931        ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/null", O_WRONLY));
   932  
   933    // Write one byte to the pipe and expect it to be successfully spliced to
   934    // /dev/null.
   935    constexpr char kSplicedByte = '.';
   936    ASSERT_THAT(WriteFd(wfd.get(), &kSplicedByte, 1),
   937                SyscallSucceedsWithValue(1));
   938    ASSERT_THAT(
   939        splice(rfd.get(), nullptr, out_fd.get(), nullptr, 1, SPLICE_F_NONBLOCK),
   940        SyscallSucceedsWithValue(1));
   941  
   942    // Expect that splicing from the pipe again fails with EAGAIN since the pipe
   943    // is now empty.
   944    ASSERT_THAT(
   945        splice(rfd.get(), nullptr, out_fd.get(), nullptr, 1, SPLICE_F_NONBLOCK),
   946        SyscallFailsWithErrno(EAGAIN));
   947  }
   948  
   949  }  // namespace
   950  
   951  }  // namespace testing
   952  }  // namespace gvisor