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, ¬ify]() { 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, ¬ify]() { 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