Skip to content

Commit 81dede8

Browse files
authored
[libc] Return errno from OFD failure paths in fcntl. (#166252)
This patch also configures fcntl lock tests to run with F_OFD_* command variants, as all existing lock tests do not exercise process-associated- or OFD-specific functionality.
1 parent 521bafc commit 81dede8

File tree

2 files changed

+94
-73
lines changed

2 files changed

+94
-73
lines changed

libc/src/__support/OSUtil/linux/fcntl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ ErrorOr<int> fcntl(int fd, int cmd, void *arg) {
6666
LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64);
6767
// On failure, return
6868
if (ret < 0)
69-
return Error(-1);
69+
return Error(-ret);
7070
// Check for overflow, i.e. the offsets are not the same when cast
7171
// to off_t from off64_t.
7272
if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||

libc/test/src/fcntl/fcntl_test.cpp

Lines changed: 93 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -94,78 +94,99 @@ TEST_F(LlvmLibcFcntlTest, FcntlSetFl) {
9494
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
9595
}
9696

97-
TEST_F(LlvmLibcFcntlTest, FcntlGetLkRead) {
98-
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
99-
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkread.test";
100-
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
101-
102-
struct flock flk, svflk;
103-
int retVal;
104-
int fd =
105-
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDONLY, S_IRWXU);
106-
ASSERT_ERRNO_SUCCESS();
107-
ASSERT_GT(fd, 0);
108-
109-
flk.l_type = F_RDLCK;
110-
flk.l_start = 0;
111-
flk.l_whence = SEEK_SET;
112-
flk.l_len = 50;
113-
114-
// copy flk into svflk
115-
svflk = flk;
116-
117-
retVal = LIBC_NAMESPACE::fcntl(fd, F_GETLK, &svflk);
118-
ASSERT_ERRNO_SUCCESS();
119-
ASSERT_GT(retVal, -1);
120-
ASSERT_NE((int)flk.l_type, F_WRLCK); // File should not be write locked.
121-
122-
retVal = LIBC_NAMESPACE::fcntl(fd, F_SETLK, &svflk);
123-
ASSERT_ERRNO_SUCCESS();
124-
ASSERT_GT(retVal, -1);
125-
126-
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
127-
}
128-
129-
TEST_F(LlvmLibcFcntlTest, FcntlGetLkWrite) {
130-
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
131-
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkwrite.test";
132-
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
133-
134-
struct flock flk, svflk;
135-
int retVal;
136-
int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
137-
ASSERT_ERRNO_SUCCESS();
138-
ASSERT_GT(fd, 0);
139-
140-
flk.l_type = F_WRLCK;
141-
flk.l_start = 0;
142-
flk.l_whence = SEEK_SET;
143-
flk.l_len = 0;
144-
145-
// copy flk into svflk
146-
svflk = flk;
147-
148-
retVal = LIBC_NAMESPACE::fcntl(fd, F_GETLK, &svflk);
149-
ASSERT_ERRNO_SUCCESS();
150-
ASSERT_GT(retVal, -1);
151-
ASSERT_NE((int)flk.l_type, F_RDLCK); // File should not be read locked.
152-
153-
retVal = LIBC_NAMESPACE::fcntl(fd, F_SETLK, &svflk);
154-
ASSERT_ERRNO_SUCCESS();
155-
ASSERT_GT(retVal, -1);
156-
157-
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
158-
}
159-
160-
TEST_F(LlvmLibcFcntlTest, UseAfterClose) {
161-
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
162-
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_use_after_close.test";
163-
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
164-
int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
165-
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
166-
ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, F_GETFL));
167-
ASSERT_ERRNO_EQ(EBADF);
168-
}
97+
/* Tests that are common between OFD and traditional variants of fcntl locks. */
98+
template <int GETLK_CMD, int SETLK_CMD>
99+
class LibcFcntlCommonLockTests : public LlvmLibcFcntlTest {
100+
public:
101+
void GetLkRead() {
102+
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
103+
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkread.test";
104+
const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
105+
106+
struct flock flk = {};
107+
struct flock svflk = {};
108+
int retVal;
109+
int fd =
110+
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDONLY, S_IRWXU);
111+
ASSERT_ERRNO_SUCCESS();
112+
ASSERT_GT(fd, 0);
113+
114+
flk.l_type = F_RDLCK;
115+
flk.l_start = 0;
116+
flk.l_whence = SEEK_SET;
117+
flk.l_len = 50;
118+
119+
// copy flk into svflk
120+
svflk = flk;
121+
122+
retVal = LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &svflk);
123+
ASSERT_ERRNO_SUCCESS();
124+
ASSERT_GT(retVal, -1);
125+
ASSERT_NE((int)svflk.l_type, F_WRLCK); // File should not be write locked.
126+
127+
retVal = LIBC_NAMESPACE::fcntl(fd, SETLK_CMD, &svflk);
128+
ASSERT_ERRNO_SUCCESS();
129+
ASSERT_GT(retVal, -1);
130+
131+
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
132+
}
133+
134+
void GetLkWrite() {
135+
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
136+
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkwrite.test";
137+
const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
138+
139+
struct flock flk = {};
140+
struct flock svflk = {};
141+
int retVal;
142+
int fd =
143+
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
144+
ASSERT_ERRNO_SUCCESS();
145+
ASSERT_GT(fd, 0);
146+
147+
flk.l_type = F_WRLCK;
148+
flk.l_start = 0;
149+
flk.l_whence = SEEK_SET;
150+
flk.l_len = 0;
151+
152+
// copy flk into svflk
153+
svflk = flk;
154+
155+
retVal = LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &svflk);
156+
ASSERT_ERRNO_SUCCESS();
157+
ASSERT_GT(retVal, -1);
158+
ASSERT_NE((int)svflk.l_type, F_RDLCK); // File should not be read locked.
159+
160+
retVal = LIBC_NAMESPACE::fcntl(fd, SETLK_CMD, &svflk);
161+
ASSERT_ERRNO_SUCCESS();
162+
ASSERT_GT(retVal, -1);
163+
164+
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
165+
}
166+
167+
void UseAfterClose() {
168+
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
169+
constexpr const char *TEST_FILE_NAME =
170+
"testdata/fcntl_use_after_close.test";
171+
const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
172+
int fd =
173+
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
174+
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
175+
ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, GETLK_CMD));
176+
ASSERT_ERRNO_EQ(EBADF);
177+
}
178+
};
179+
180+
#define COMMON_LOCK_TESTS(NAME, GETLK, SETLK) \
181+
using NAME = LibcFcntlCommonLockTests<GETLK, SETLK>; \
182+
TEST_F(NAME, GetLkRead) { GetLkRead(); } \
183+
TEST_F(NAME, GetLkWrite) { GetLkWrite(); } \
184+
TEST_F(NAME, UseAfterClose) { UseAfterClose(); } \
185+
static_assert(true, "Require semicolon.")
186+
187+
COMMON_LOCK_TESTS(LlvmLibcFcntlProcessAssociatedLockTest, F_GETLK, F_SETLK);
188+
COMMON_LOCK_TESTS(LlvmLibcFcntlOpenFileDescriptionLockTest, F_OFD_GETLK,
189+
F_OFD_SETLK);
169190

170191
TEST_F(LlvmLibcFcntlTest, SetGetOwnerTest) {
171192
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;

0 commit comments

Comments
 (0)