179 lines · cpp
1//===-- Unittests for syscalls --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/unistd/syscall.h"10#include "test/UnitTest/ErrnoCheckingTest.h"11#include "test/UnitTest/ErrnoSetterMatcher.h"12#include "test/UnitTest/Test.h"13 14#include "hdr/fcntl_macros.h"15#include <sys/stat.h> // For S_* flags.16#include <sys/syscall.h> // For syscall numbers.17#include <unistd.h>18 19using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;20using LlvmLibcSyscallTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;21 22// We only do a smoke test here. Actual functionality tests are23// done by the unit tests of the syscall wrappers like mmap.24// The goal is to test syscalls with a wide number of args.25 26// There is no function named "syscall" in llvm-libc, we instead use a macro to27// set up the arguments properly. We still need to specify the namespace though28// because the macro generates a call to the actual internal function29// (__llvm_libc_syscall) which is inside the namespace.30TEST_F(LlvmLibcSyscallTest, TrivialCall) {31 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_gettid), 0l);32 ASSERT_ERRNO_SUCCESS();33}34 35TEST_F(LlvmLibcSyscallTest, SymlinkCreateDestroy) {36 constexpr const char LINK_VAL[] = "syscall_readlink_test_value";37 constexpr const char LINK[] = "testdata/syscall_readlink.test.link";38 39#ifdef SYS_symlink40 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_symlink, LINK_VAL, LINK), 0l);41#elif defined(SYS_symlinkat)42 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_symlinkat, LINK_VAL, AT_FDCWD, LINK),43 0l);44#else45#error "symlink and symlinkat syscalls not available."46#endif47 ASSERT_ERRNO_SUCCESS();48 49 char buf[sizeof(LINK_VAL)];50 51#ifdef SYS_readlink52 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_readlink, LINK, buf, sizeof(buf)), 0l);53#elif defined(SYS_readlinkat)54 ASSERT_GE(55 LIBC_NAMESPACE::syscall(SYS_readlinkat, AT_FDCWD, LINK, buf, sizeof(buf)),56 0l);57#endif58 ASSERT_ERRNO_SUCCESS();59 60#ifdef SYS_unlink61 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, LINK), 0l);62#elif defined(SYS_unlinkat)63 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, LINK, 0), 0l);64#else65#error "unlink and unlinkat syscalls not available."66#endif67 ASSERT_ERRNO_SUCCESS();68}69 70TEST_F(LlvmLibcSyscallTest, FileReadWrite) {71 constexpr const char HELLO[] = "hello";72 constexpr int HELLO_SIZE = sizeof(HELLO);73 74 constexpr const char *TEST_FILE = "testdata/syscall_pread_pwrite.test";75 76#ifdef SYS_open77 long fd =78 LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);79#elif defined(SYS_openat)80 long fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_FILE,81 O_WRONLY | O_CREAT, S_IRWXU);82#else83#error "open and openat syscalls not available."84#endif85 ASSERT_GT(fd, 0l);86 ASSERT_ERRNO_SUCCESS();87 88 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_pwrite64, fd, HELLO, HELLO_SIZE, 0),89 0l);90 ASSERT_ERRNO_SUCCESS();91 92 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_fsync, fd), 0l);93 ASSERT_ERRNO_SUCCESS();94 95 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, fd), 0l);96 ASSERT_ERRNO_SUCCESS();97}98 99TEST_F(LlvmLibcSyscallTest, FileLinkCreateDestroy) {100 constexpr const char *TEST_DIR = "testdata";101 constexpr const char *TEST_FILE = "syscall_linkat.test";102 constexpr const char *TEST_FILE_PATH = "testdata/syscall_linkat.test";103 constexpr const char *TEST_FILE_LINK = "syscall_linkat.test.link";104 constexpr const char *TEST_FILE_LINK_PATH =105 "testdata/syscall_linkat.test.link";106 107 // The test strategy is as follows:108 // 1. Create a normal file109 // 2. Create a link to that file.110 // 3. Open the link to check that the link was created.111 // 4. Cleanup the file and its link.112 113#ifdef SYS_open114 long write_fd = LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE_PATH,115 O_WRONLY | O_CREAT, S_IRWXU);116#elif defined(SYS_openat)117 long write_fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_FILE_PATH,118 O_WRONLY | O_CREAT, S_IRWXU);119#else120#error "open and openat syscalls not available."121#endif122 ASSERT_GT(write_fd, 0l);123 ASSERT_ERRNO_SUCCESS();124 125 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, write_fd), 0l);126 ASSERT_ERRNO_SUCCESS();127 128#ifdef SYS_open129 long dir_fd = LIBC_NAMESPACE::syscall(SYS_open, TEST_DIR, O_DIRECTORY, 0);130#elif defined(SYS_openat)131 long dir_fd =132 LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_DIR, O_DIRECTORY, 0);133#else134#error "open and openat syscalls not available."135#endif136 ASSERT_GT(dir_fd, 0l);137 ASSERT_ERRNO_SUCCESS();138 139 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_linkat, dir_fd, TEST_FILE, dir_fd,140 TEST_FILE_LINK, 0),141 0l);142 ASSERT_ERRNO_SUCCESS();143#ifdef SYS_open144 long link_fd =145 LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE_LINK_PATH, O_PATH, 0);146#elif defined(SYS_openat)147 long link_fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD,148 TEST_FILE_LINK_PATH, O_PATH, 0);149#else150#error "open and openat syscalls not available."151#endif152 ASSERT_GT(link_fd, 0l);153 ASSERT_ERRNO_SUCCESS();154 155#ifdef SYS_unlink156 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, TEST_FILE_PATH), 0l);157#elif defined(SYS_unlinkat)158 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, TEST_FILE_PATH, 0),159 0l);160#else161#error "unlink and unlinkat syscalls not available."162#endif163 ASSERT_ERRNO_SUCCESS();164 165#ifdef SYS_unlink166 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, TEST_FILE_LINK_PATH), 0l);167#elif defined(SYS_unlinkat)168 ASSERT_GE(169 LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, TEST_FILE_LINK_PATH, 0),170 0l);171#else172#error "unlink and unlinkat syscalls not available."173#endif174 ASSERT_ERRNO_SUCCESS();175 176 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, dir_fd), 0l);177 ASSERT_ERRNO_SUCCESS();178}179