• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-exception
6 //
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 
19 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
20 using LlvmLibcSyscallTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
21 
22 // We only do a smoke test here. Actual functionality tests are
23 // 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 to
27 // set up the arguments properly. We still need to specify the namespace though
28 // because the macro generates a call to the actual internal function
29 // (__llvm_libc_syscall) which is inside the namespace.
TEST_F(LlvmLibcSyscallTest,TrivialCall)30 TEST_F(LlvmLibcSyscallTest, TrivialCall) {
31   ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_gettid), 0l);
32   ASSERT_ERRNO_SUCCESS();
33 }
34 
TEST_F(LlvmLibcSyscallTest,SymlinkCreateDestroy)35 TEST_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_symlink
40   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 #else
45 #error "symlink and symlinkat syscalls not available."
46 #endif
47   ASSERT_ERRNO_SUCCESS();
48 
49   char buf[sizeof(LINK_VAL)];
50 
51 #ifdef SYS_readlink
52   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 #endif
58   ASSERT_ERRNO_SUCCESS();
59 
60 #ifdef SYS_unlink
61   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 #else
65 #error "unlink and unlinkat syscalls not available."
66 #endif
67   ASSERT_ERRNO_SUCCESS();
68 }
69 
TEST_F(LlvmLibcSyscallTest,FileReadWrite)70 TEST_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_open
77   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 #else
83 #error "open and openat syscalls not available."
84 #endif
85   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 
TEST_F(LlvmLibcSyscallTest,FileLinkCreateDestroy)99 TEST_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 file
109   //   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_open
114   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 #else
120 #error "open and openat syscalls not available."
121 #endif
122   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_open
129   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 #else
134 #error "open and openat syscalls not available."
135 #endif
136   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_open
144   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 #else
150 #error "open and openat syscalls not available."
151 #endif
152   ASSERT_GT(link_fd, 0l);
153   ASSERT_ERRNO_SUCCESS();
154 
155 #ifdef SYS_unlink
156   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 #else
161 #error "unlink and unlinkat syscalls not available."
162 #endif
163   ASSERT_ERRNO_SUCCESS();
164 
165 #ifdef SYS_unlink
166   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 #else
172 #error "unlink and unlinkat syscalls not available."
173 #endif
174   ASSERT_ERRNO_SUCCESS();
175 
176   ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, dir_fd), 0l);
177   ASSERT_ERRNO_SUCCESS();
178 }
179