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