1616#include < fcntl.h>
1717#include < linux/unistd.h>
1818#include < sys/socket.h>
19+ #include < sys/syscall.h>
1920#include < sys/types.h>
2021#include < unistd.h>
2122
2223#include " gtest/gtest.h"
24+ #include " test/util/cleanup.h"
2325#include " test/util/temp_path.h"
2426#include " test/util/test_util.h"
2527
@@ -28,7 +30,6 @@ namespace testing {
2830
2931namespace {
3032
31- // TODO(gvisor.dev/issue/2370): This test is currently very rudimentary.
3233class Pwrite64 : public ::testing::Test {
3334 void SetUp () override {
3435 name_ = NewTempAbsPath ();
@@ -87,6 +88,87 @@ TEST_F(Pwrite64, Pwrite64WithOpath) {
8788 SyscallFailsWithErrno (EBADF));
8889}
8990
91+ // Test that pwrite64 with a nullptr buffer fails with EFAULT.
92+ TEST_F (Pwrite64, NullBuffer) {
93+ FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE (Open (name_.c_str (), O_RDWR));
94+
95+ // Use raw syscall to bypass libc's nonnull annotation.
96+ EXPECT_THAT (syscall (SYS_pwrite64, fd.get (), nullptr , 1 , 0 ),
97+ SyscallFailsWithErrno (EFAULT));
98+ }
99+
100+ // Test that pwrite64 with zero length and nullptr buffer succeeds.
101+ TEST_F (Pwrite64, ZeroLengthNullBuffer) {
102+ FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE (Open (name_.c_str (), O_RDWR));
103+ EXPECT_THAT (pwrite64 (fd.get (), nullptr , 0 , 0 ), SyscallSucceedsWithValue (0 ));
104+ }
105+
106+ // Test that pwrite64 to a closed fd fails with EBADF.
107+ TEST_F (Pwrite64, ClosedFd) {
108+ FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE (Open (name_.c_str (), O_RDWR));
109+ int raw_fd = fd.get ();
110+ fd.reset ();
111+
112+ char buf[16 ] = {};
113+ EXPECT_THAT (pwrite64 (raw_fd, buf, sizeof (buf), 0 ),
114+ SyscallFailsWithErrno (EBADF));
115+ }
116+
117+ // Test that pwrite64 to a read-only fd fails with EBADF.
118+ TEST_F (Pwrite64, ReadOnlyFd) {
119+ FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE (Open (name_.c_str (), O_RDONLY));
120+
121+ char buf[16 ] = {};
122+ EXPECT_THAT (pwrite64 (fd.get (), buf, sizeof (buf), 0 ),
123+ SyscallFailsWithErrno (EBADF));
124+ }
125+
126+ // Test that pwrite64 does not change file offset.
127+ TEST_F (Pwrite64, DoesNotChangeOffset) {
128+ FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE (Open (name_.c_str (), O_RDWR));
129+
130+ // Set initial offset.
131+ const off_t initial_offset = 50 ;
132+ ASSERT_THAT (lseek (fd.get (), initial_offset, SEEK_SET),
133+ SyscallSucceedsWithValue (initial_offset));
134+
135+ char buf[16 ] = " test data" ;
136+ EXPECT_THAT (pwrite64 (fd.get (), buf, sizeof (buf), 100 ),
137+ SyscallSucceedsWithValue (sizeof (buf)));
138+
139+ // Offset should remain unchanged.
140+ EXPECT_THAT (lseek (fd.get (), 0 , SEEK_CUR),
141+ SyscallSucceedsWithValue (initial_offset));
142+ }
143+
144+ // Test that pwrite64 to a pipe fails with ESPIPE.
145+ TEST_F (Pwrite64, Pipe) {
146+ int pipe_fds[2 ];
147+ ASSERT_THAT (pipe (pipe_fds), SyscallSucceeds ());
148+ auto cleanup = Cleanup ([&pipe_fds] {
149+ close (pipe_fds[0 ]);
150+ close (pipe_fds[1 ]);
151+ });
152+
153+ char buf[16 ] = {};
154+ EXPECT_THAT (pwrite64 (pipe_fds[1 ], buf, sizeof (buf), 0 ),
155+ SyscallFailsWithErrno (ESPIPE));
156+ }
157+
158+ // Test that pwrite64 to a socket fails with ESPIPE.
159+ TEST_F (Pwrite64, Socket) {
160+ int sock_fds[2 ];
161+ ASSERT_THAT (socketpair (AF_UNIX, SOCK_STREAM, 0 , sock_fds), SyscallSucceeds ());
162+ auto cleanup = Cleanup ([&sock_fds] {
163+ close (sock_fds[0 ]);
164+ close (sock_fds[1 ]);
165+ });
166+
167+ char buf[16 ] = {};
168+ EXPECT_THAT (pwrite64 (sock_fds[0 ], buf, sizeof (buf), 0 ),
169+ SyscallFailsWithErrno (ESPIPE));
170+ }
171+
90172} // namespace
91173
92174} // namespace testing
0 commit comments