[ELF] Refine isExported/isPreemptible condition
[llvm-project.git] / flang / unittests / Runtime / AccessTest.cpp
blobc2a2d7d398220ccb337ef8d957cde3d3b580cc9a
1 //===-- flang/unittests/Runtime/AccessTest.cpp ----------------------------===//
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 //===----------------------------------------------------------------------===//
9 // TODO: ACCESS is not yet implemented on Windows
10 #ifndef _WIN32
12 #include "CrashHandlerFixture.h"
13 #include "gtest/gtest.h"
14 #include "flang/Runtime/extensions.h"
15 #include "llvm/ADT/Twine.h"
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
22 namespace {
24 struct AccessTests : public CrashHandlerFixture {};
26 struct AccessType {
27 bool read{false};
28 bool write{false};
29 bool execute{false};
30 bool exists{false};
33 } // namespace
35 static bool userSkipsPermissionChecks() {
36 // The tests in this file assume normal permission checks apply to the user
37 // running the tests. This isn't true when the test is run by root.
38 return geteuid() == 0;
41 static std::string addPIDSuffix(const char *name) {
42 std::stringstream ss;
43 ss << name;
44 ss << '.';
46 ss << getpid();
48 return ss.str();
51 static bool exists(const std::string &path) {
52 return access(path.c_str(), F_OK) == 0;
55 // Implementation of std::filesystem::temp_directory_path adapted from libcxx
56 // See llvm-project/libcxx/src/filesystem/operations.cpp
57 // Using std::filesystem is inconvenient because the required flags are not
58 // consistent accross compilers and CMake doesn't have built in support to
59 // determine the correct flags.
60 static const char *temp_directory_path() {
61 // TODO: Windows
62 const char *env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
63 const char *ret = nullptr;
65 for (auto &ep : env_paths) {
66 if ((ret = getenv(ep))) {
67 break;
71 if (ret == nullptr) {
72 #if defined(__ANDROID__)
73 ret = "/data/local/tmp";
74 #else
75 ret = "/tmp";
76 #endif
79 assert(exists(ret));
80 return ret;
83 static std::string createTemporaryFile(
84 const char *name, const AccessType &accessType) {
85 std::string path =
86 (llvm::Twine{temp_directory_path()} + "/" + addPIDSuffix(name)).str();
88 // O_CREAT | O_EXCL enforces that this file is newly created by this call.
89 // This feels risky. If we don't have permission to create files in the
90 // temporary directory or if the files already exist, the test will fail.
91 // But we can't use std::tmpfile() because we need a path to the file and
92 // to control the filesystem permissions
93 mode_t mode{0};
94 if (accessType.read) {
95 mode |= S_IRUSR;
97 if (accessType.write) {
98 mode |= S_IWUSR;
100 if (accessType.execute) {
101 mode |= S_IXUSR;
104 int file = open(path.c_str(), O_CREAT | O_EXCL, mode);
105 if (file == -1) {
106 return {};
109 close(file);
111 return path;
114 static std::int64_t callAccess(
115 const std::string &path, const AccessType &accessType) {
116 const char *cpath{path.c_str()};
117 std::int64_t pathlen = std::strlen(cpath);
119 std::string mode;
120 if (accessType.read) {
121 mode += 'r';
123 if (accessType.write) {
124 mode += 'w';
126 if (accessType.execute) {
127 mode += 'x';
129 if (accessType.exists) {
130 mode += ' ';
133 const char *cmode = mode.c_str();
134 std::int64_t modelen = std::strlen(cmode);
136 return FORTRAN_PROCEDURE_NAME(access)(cpath, pathlen, cmode, modelen);
139 TEST(AccessTests, TestExists) {
140 AccessType accessType;
141 accessType.exists = true;
143 std::string path = createTemporaryFile(__func__, accessType);
144 ASSERT_FALSE(path.empty());
146 std::int64_t res = callAccess(path, accessType);
148 ASSERT_EQ(unlink(path.c_str()), 0);
150 ASSERT_EQ(res, 0);
153 TEST(AccessTests, TestNotExists) {
154 std::string nonExistant{addPIDSuffix(__func__)};
155 ASSERT_FALSE(exists(nonExistant));
157 AccessType accessType;
158 accessType.exists = true;
159 std::int64_t res = callAccess(nonExistant, accessType);
161 ASSERT_NE(res, 0);
164 TEST(AccessTests, TestRead) {
165 AccessType accessType;
166 accessType.read = true;
168 std::string path = createTemporaryFile(__func__, accessType);
169 ASSERT_FALSE(path.empty());
171 std::int64_t res = callAccess(path, accessType);
173 ASSERT_EQ(unlink(path.c_str()), 0);
175 if (userSkipsPermissionChecks()) {
176 return;
179 ASSERT_EQ(res, 0);
182 TEST(AccessTests, TestNotRead) {
183 AccessType accessType;
184 accessType.read = false;
186 std::string path = createTemporaryFile(__func__, accessType);
187 ASSERT_FALSE(path.empty());
189 accessType.read = true;
190 std::int64_t res = callAccess(path, accessType);
192 ASSERT_EQ(unlink(path.c_str()), 0);
194 if (userSkipsPermissionChecks()) {
195 return;
198 ASSERT_NE(res, 0);
201 TEST(AccessTests, TestWrite) {
202 AccessType accessType;
203 accessType.write = true;
205 std::string path = createTemporaryFile(__func__, accessType);
206 ASSERT_FALSE(path.empty());
208 std::int64_t res = callAccess(path, accessType);
210 ASSERT_EQ(unlink(path.c_str()), 0);
212 if (userSkipsPermissionChecks()) {
213 return;
216 ASSERT_EQ(res, 0);
219 TEST(AccessTests, TestNotWrite) {
220 AccessType accessType;
221 accessType.write = false;
223 std::string path = createTemporaryFile(__func__, accessType);
224 ASSERT_FALSE(path.empty());
226 accessType.write = true;
227 std::int64_t res = callAccess(path, accessType);
229 ASSERT_EQ(unlink(path.c_str()), 0);
231 if (userSkipsPermissionChecks()) {
232 return;
235 ASSERT_NE(res, 0);
238 TEST(AccessTests, TestReadWrite) {
239 AccessType accessType;
240 accessType.read = true;
241 accessType.write = true;
243 std::string path = createTemporaryFile(__func__, accessType);
244 ASSERT_FALSE(path.empty());
246 std::int64_t res = callAccess(path, accessType);
248 ASSERT_EQ(unlink(path.c_str()), 0);
250 if (userSkipsPermissionChecks()) {
251 return;
254 ASSERT_EQ(res, 0);
257 TEST(AccessTests, TestNotReadWrite0) {
258 AccessType accessType;
259 accessType.read = false;
260 accessType.write = false;
262 std::string path = createTemporaryFile(__func__, accessType);
263 ASSERT_FALSE(path.empty());
265 accessType.read = true;
266 accessType.write = true;
267 std::int64_t res = callAccess(path, accessType);
269 ASSERT_EQ(unlink(path.c_str()), 0);
271 if (userSkipsPermissionChecks()) {
272 return;
275 ASSERT_NE(res, 0);
278 TEST(AccessTests, TestNotReadWrite1) {
279 AccessType accessType;
280 accessType.read = true;
281 accessType.write = false;
283 std::string path = createTemporaryFile(__func__, accessType);
284 ASSERT_FALSE(path.empty());
286 accessType.read = true;
287 accessType.write = true;
288 std::int64_t res = callAccess(path, accessType);
290 ASSERT_EQ(unlink(path.c_str()), 0);
292 if (userSkipsPermissionChecks()) {
293 return;
296 ASSERT_NE(res, 0);
299 TEST(AccessTests, TestNotReadWrite2) {
300 AccessType accessType;
301 accessType.read = false;
302 accessType.write = true;
304 std::string path = createTemporaryFile(__func__, accessType);
305 ASSERT_FALSE(path.empty());
307 accessType.read = true;
308 accessType.write = true;
309 std::int64_t res = callAccess(path, accessType);
311 ASSERT_EQ(unlink(path.c_str()), 0);
313 if (userSkipsPermissionChecks()) {
314 return;
317 ASSERT_NE(res, 0);
320 TEST(AccessTests, TestExecute) {
321 AccessType accessType;
322 accessType.execute = true;
324 std::string path = createTemporaryFile(__func__, accessType);
325 ASSERT_FALSE(path.empty());
327 std::int64_t res = callAccess(path, accessType);
329 ASSERT_EQ(unlink(path.c_str()), 0);
331 if (userSkipsPermissionChecks()) {
332 return;
335 ASSERT_EQ(res, 0);
338 TEST(AccessTests, TestNotExecute) {
339 AccessType accessType;
340 accessType.execute = false;
342 std::string path = createTemporaryFile(__func__, accessType);
343 ASSERT_FALSE(path.empty());
345 accessType.execute = true;
346 std::int64_t res = callAccess(path, accessType);
348 ASSERT_EQ(unlink(path.c_str()), 0);
350 if (userSkipsPermissionChecks()) {
351 return;
354 ASSERT_NE(res, 0);
357 TEST(AccessTests, TestRWX) {
358 AccessType accessType;
359 accessType.read = true;
360 accessType.write = true;
361 accessType.execute = true;
363 std::string path = createTemporaryFile(__func__, accessType);
364 ASSERT_FALSE(path.empty());
366 std::int64_t res = callAccess(path, accessType);
368 ASSERT_EQ(unlink(path.c_str()), 0);
370 if (userSkipsPermissionChecks()) {
371 return;
374 ASSERT_EQ(res, 0);
377 TEST(AccessTests, TestNotRWX0) {
378 AccessType accessType;
379 accessType.read = false;
380 accessType.write = false;
381 accessType.execute = false;
383 std::string path = createTemporaryFile(__func__, accessType);
384 ASSERT_FALSE(path.empty());
386 accessType.read = true;
387 accessType.write = true;
388 accessType.execute = true;
389 std::int64_t res = callAccess(path, accessType);
391 ASSERT_EQ(unlink(path.c_str()), 0);
393 if (userSkipsPermissionChecks()) {
394 return;
397 ASSERT_NE(res, 0);
400 TEST(AccessTests, TestNotRWX1) {
401 AccessType accessType;
402 accessType.read = true;
403 accessType.write = false;
404 accessType.execute = false;
406 std::string path = createTemporaryFile(__func__, accessType);
407 ASSERT_FALSE(path.empty());
409 accessType.read = true;
410 accessType.write = true;
411 accessType.execute = true;
412 std::int64_t res = callAccess(path, accessType);
414 ASSERT_EQ(unlink(path.c_str()), 0);
416 if (userSkipsPermissionChecks()) {
417 return;
420 ASSERT_NE(res, 0);
423 TEST(AccessTests, TestNotRWX2) {
424 AccessType accessType;
425 accessType.read = true;
426 accessType.write = true;
427 accessType.execute = false;
429 std::string path = createTemporaryFile(__func__, accessType);
430 ASSERT_FALSE(path.empty());
432 accessType.read = true;
433 accessType.write = true;
434 accessType.execute = true;
435 std::int64_t res = callAccess(path, accessType);
437 ASSERT_EQ(unlink(path.c_str()), 0);
439 if (userSkipsPermissionChecks()) {
440 return;
443 ASSERT_NE(res, 0);
446 TEST(AccessTests, TestNotRWX3) {
447 AccessType accessType;
448 accessType.read = true;
449 accessType.write = false;
450 accessType.execute = true;
452 std::string path = createTemporaryFile(__func__, accessType);
453 ASSERT_FALSE(path.empty());
455 accessType.read = true;
456 accessType.write = true;
457 accessType.execute = true;
458 std::int64_t res = callAccess(path, accessType);
460 ASSERT_EQ(unlink(path.c_str()), 0);
462 if (userSkipsPermissionChecks()) {
463 return;
466 ASSERT_NE(res, 0);
469 TEST(AccessTests, TestNotRWX4) {
470 AccessType accessType;
471 accessType.read = false;
472 accessType.write = true;
473 accessType.execute = true;
475 std::string path = createTemporaryFile(__func__, accessType);
476 ASSERT_FALSE(path.empty());
478 accessType.read = true;
479 accessType.write = true;
480 accessType.execute = true;
481 std::int64_t res = callAccess(path, accessType);
483 ASSERT_EQ(unlink(path.c_str()), 0);
485 if (userSkipsPermissionChecks()) {
486 return;
489 ASSERT_NE(res, 0);
492 #endif // !_WIN32