Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libc/src/__support/OSUtil/linux/fcntl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ ErrorOr<int> fcntl(int fd, int cmd, void *arg) {
LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64);
// On failure, return
if (ret < 0)
return Error(-ret);
return Error(-1);
// Check for overflow, i.e. the offsets are not the same when cast
// to off_t from off64_t.
if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
Expand Down
165 changes: 72 additions & 93 deletions libc/test/src/fcntl/fcntl_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,99 +94,78 @@ TEST_F(LlvmLibcFcntlTest, FcntlSetFl) {
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}

/* Tests that are common between OFD and traditional variants of fcntl locks. */
template <int GETLK_CMD, int SETLK_CMD>
class LibcFcntlCommonLockTests : public LlvmLibcFcntlTest {
public:
void GetLkRead() {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkread.test";
const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);

struct flock flk = {};
struct flock svflk = {};
int retVal;
int fd =
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDONLY, S_IRWXU);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);

flk.l_type = F_RDLCK;
flk.l_start = 0;
flk.l_whence = SEEK_SET;
flk.l_len = 50;

// copy flk into svflk
svflk = flk;

retVal = LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);
ASSERT_NE((int)svflk.l_type, F_WRLCK); // File should not be write locked.

retVal = LIBC_NAMESPACE::fcntl(fd, SETLK_CMD, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);

ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}

void GetLkWrite() {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkwrite.test";
const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);

struct flock flk = {};
struct flock svflk = {};
int retVal;
int fd =
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);

flk.l_type = F_WRLCK;
flk.l_start = 0;
flk.l_whence = SEEK_SET;
flk.l_len = 0;

// copy flk into svflk
svflk = flk;

retVal = LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);
ASSERT_NE((int)svflk.l_type, F_RDLCK); // File should not be read locked.

retVal = LIBC_NAMESPACE::fcntl(fd, SETLK_CMD, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);

ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}

void UseAfterClose() {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE_NAME =
"testdata/fcntl_use_after_close.test";
const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
int fd =
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, GETLK_CMD));
ASSERT_ERRNO_EQ(EBADF);
}
};

#define COMMON_LOCK_TESTS(NAME, GETLK, SETLK) \
using NAME = LibcFcntlCommonLockTests<GETLK, SETLK>; \
TEST_F(NAME, GetLkRead) { GetLkRead(); } \
TEST_F(NAME, GetLkWrite) { GetLkWrite(); } \
TEST_F(NAME, UseAfterClose) { UseAfterClose(); } \
static_assert(true, "Require semicolon.")

COMMON_LOCK_TESTS(LlvmLibcFcntlProcessAssociatedLockTest, F_GETLK, F_SETLK);
COMMON_LOCK_TESTS(LlvmLibcFcntlOpenFileDescriptionLockTest, F_OFD_GETLK,
F_OFD_SETLK);
TEST_F(LlvmLibcFcntlTest, FcntlGetLkRead) {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkread.test";
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);

struct flock flk, svflk;
int retVal;
int fd =
LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDONLY, S_IRWXU);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);

flk.l_type = F_RDLCK;
flk.l_start = 0;
flk.l_whence = SEEK_SET;
flk.l_len = 50;

// copy flk into svflk
svflk = flk;

retVal = LIBC_NAMESPACE::fcntl(fd, F_GETLK, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);
ASSERT_NE((int)flk.l_type, F_WRLCK); // File should not be write locked.

retVal = LIBC_NAMESPACE::fcntl(fd, F_SETLK, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);

ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}

TEST_F(LlvmLibcFcntlTest, FcntlGetLkWrite) {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkwrite.test";
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);

struct flock flk, svflk;
int retVal;
int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);

flk.l_type = F_WRLCK;
flk.l_start = 0;
flk.l_whence = SEEK_SET;
flk.l_len = 0;

// copy flk into svflk
svflk = flk;

retVal = LIBC_NAMESPACE::fcntl(fd, F_GETLK, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);
ASSERT_NE((int)flk.l_type, F_RDLCK); // File should not be read locked.

retVal = LIBC_NAMESPACE::fcntl(fd, F_SETLK, &svflk);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(retVal, -1);

ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}

TEST_F(LlvmLibcFcntlTest, UseAfterClose) {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE_NAME = "testdata/fcntl_use_after_close.test";
auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, F_GETFL));
ASSERT_ERRNO_EQ(EBADF);
}

TEST_F(LlvmLibcFcntlTest, SetGetOwnerTest) {
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
Expand Down
Loading