aboutsummaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorSiva Chandra Reddy <sivachandra@google.com>2022-12-14 22:37:28 +0000
committerSiva Chandra Reddy <sivachandra@google.com>2022-12-15 21:05:40 +0000
commit9b29436a1c546bb16632d19e5a6f1edde3b6b2b2 (patch)
treec4c04a300082b64ba4cb946a7699186c6da299df /libc
parentc4b7e8a035d524c797bed79b3c7aeae0707e07b5 (diff)
downloadllvm-9b29436a1c546bb16632d19e5a6f1edde3b6b2b2.zip
llvm-9b29436a1c546bb16632d19e5a6f1edde3b6b2b2.tar.gz
llvm-9b29436a1c546bb16632d19e5a6f1edde3b6b2b2.tar.bz2
[libc] Handle allocation failures in the dirent API gracefully.
Along the way, setting of errno has been moved out of the internal code. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D140078
Diffstat (limited to 'libc')
-rw-r--r--libc/src/__support/CPP/CMakeLists.txt8
-rw-r--r--libc/src/__support/CPP/new.cpp30
-rw-r--r--libc/src/__support/CPP/new.h25
-rw-r--r--libc/src/__support/File/CMakeLists.txt3
-rw-r--r--libc/src/__support/File/dir.cpp41
-rw-r--r--libc/src/__support/File/dir.h31
-rw-r--r--libc/src/__support/File/linux_dir.cpp19
-rw-r--r--libc/src/dirent/CMakeLists.txt3
-rw-r--r--libc/src/dirent/closedir.cpp8
-rw-r--r--libc/src/dirent/opendir.cpp8
-rw-r--r--libc/src/dirent/readdir.cpp8
11 files changed, 140 insertions, 44 deletions
diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index d84492f..3bab78c 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -100,3 +100,11 @@ add_header_library(
HDRS
expected.h
)
+
+add_object_library(
+ new
+ SRCS
+ new.cpp
+ HDRS
+ new.h
+)
diff --git a/libc/src/__support/CPP/new.cpp b/libc/src/__support/CPP/new.cpp
new file mode 100644
index 0000000..5a40d4a
--- /dev/null
+++ b/libc/src/__support/CPP/new.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of custom operator delete --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "new.h"
+#include <stdlib.h>
+
+void operator delete(void *mem) noexcept { ::free(mem); }
+
+void operator delete(void *mem, std::align_val_t) noexcept { ::free(mem); }
+
+void operator delete(void *mem, size_t) noexcept { ::free(mem); }
+
+void operator delete(void *mem, size_t, std::align_val_t) noexcept {
+ ::free(mem);
+}
+
+void operator delete[](void *mem) noexcept { ::free(mem); }
+
+void operator delete[](void *mem, std::align_val_t) noexcept { ::free(mem); }
+
+void operator delete[](void *mem, size_t) noexcept { ::free(mem); }
+
+void operator delete[](void *mem, size_t, std::align_val_t) noexcept {
+ ::free(mem);
+}
diff --git a/libc/src/__support/CPP/new.h b/libc/src/__support/CPP/new.h
index 3becb9f..7b23f08 100644
--- a/libc/src/__support/CPP/new.h
+++ b/libc/src/__support/CPP/new.h
@@ -69,4 +69,29 @@ inline void *operator new[](size_t size, std::align_val_t align,
return __llvm_libc::AllocChecker::aligned_alloc(size, align, ac);
}
+// The ideal situation would be to define the various flavors of operator delete
+// inline like we do with operator new above. However, since we need operator
+// delete prototypes to match those specified by the C++ standard, we cannot
+// define them inline as the C++ standard does not allow inline definitions of
+// replacement operator delete implementations. Note also that we assign a
+// special linkage name to each of these replacement operator delete functions.
+// This is because, if we do not give them a special libc internal linkage name,
+// they will replace operator delete for the entire application. Including this
+// header file in all libc source files where operator delete is called ensures
+// that only libc call sites use these replacement operator delete functions.
+void operator delete(void *) noexcept __asm__("__llvm_libc_delete");
+void operator delete(void *, std::align_val_t) noexcept
+ __asm__("__llvm_libc_delete_aligned");
+void operator delete(void *, size_t) noexcept
+ __asm__("__llvm_libc_delete_sized");
+void operator delete(void *, size_t, std::align_val_t) noexcept
+ __asm__("__llvm_libc_delete_sized_aligned");
+void operator delete[](void *) noexcept __asm__("__llvm_libc_delete_array");
+void operator delete[](void *, std::align_val_t) noexcept
+ __asm__("__llvm_libc_delete_array_aligned");
+void operator delete[](void *, size_t) noexcept
+ __asm__("__llvm_libc_delete_array_sized");
+void operator delete[](void *, size_t, std::align_val_t) noexcept
+ __asm__("__llvm_libc_delete_array_sized_aligned");
+
#endif // LLVM_LIBC_SRC_SUPPORT_CPP_NEW_H
diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt
index dd99e0d..ef56a76 100644
--- a/libc/src/__support/File/CMakeLists.txt
+++ b/libc/src/__support/File/CMakeLists.txt
@@ -24,6 +24,7 @@ add_object_library(
HDRS
dir.h
DEPENDS
+ libc.src.__support.CPP.new
libc.src.__support.CPP.span
libc.src.__support.threads.mutex
)
@@ -56,6 +57,6 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}_dir.cpp)
libc.include.fcntl
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
- libc.src.errno.errno
+ libc.src.__support.error_or
)
endif()
diff --git a/libc/src/__support/File/dir.cpp b/libc/src/__support/File/dir.cpp
index bfd9b4c..a473704 100644
--- a/libc/src/__support/File/dir.cpp
+++ b/libc/src/__support/File/dir.cpp
@@ -8,32 +8,38 @@
#include "dir.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/error_or.h"
+
+#include <errno.h>
#include <stdlib.h>
namespace __llvm_libc {
-Dir *Dir::open(const char *path) {
- int fd = platform_opendir(path);
- if (fd < 0)
- return nullptr;
-
- Dir *dir = reinterpret_cast<Dir *>(malloc(sizeof(Dir)));
- dir->fd = fd;
- dir->readptr = 0;
- dir->fillsize = 0;
- Mutex::init(&dir->mutex, false, false, false);
+ErrorOr<Dir *> Dir::open(const char *path) {
+ auto fd = platform_opendir(path);
+ if (!fd)
+ return __llvm_libc::Error(fd.error());
+ __llvm_libc::AllocChecker ac;
+ Dir *dir = new (ac) Dir(fd);
+ if (!ac)
+ return __llvm_libc::Error(ENOMEM);
return dir;
}
-struct ::dirent *Dir::read() {
+ErrorOr<struct ::dirent *> Dir::read() {
MutexLock lock(&mutex);
if (readptr >= fillsize) {
- fillsize = platform_fetch_dirents(fd, buffer);
- if (fillsize == 0)
- return nullptr;
+ auto readsize = platform_fetch_dirents(fd, buffer);
+ if (!readsize)
+ return __llvm_libc::Error(readsize.error());
+ fillsize = readsize;
readptr = 0;
}
+ if (fillsize == 0)
+ return nullptr;
+
struct ::dirent *d = reinterpret_cast<struct ::dirent *>(buffer + readptr);
#ifdef __unix__
// The d_reclen field is available on Linux but not required by POSIX.
@@ -48,10 +54,11 @@ struct ::dirent *Dir::read() {
int Dir::close() {
{
MutexLock lock(&mutex);
- if (!platform_closedir(fd))
- return -1;
+ int retval = platform_closedir(fd);
+ if (retval != 0)
+ return retval;
}
- free(this);
+ delete this;
return 0;
}
diff --git a/libc/src/__support/File/dir.h b/libc/src/__support/File/dir.h
index c5f3750..57d31935 100644
--- a/libc/src/__support/File/dir.h
+++ b/libc/src/__support/File/dir.h
@@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC_SUPPORT_FILE_DIR_H
#include "src/__support/CPP/span.h"
+#include "src/__support/error_or.h"
#include "src/__support/threads/mutex.h"
#include <dirent.h>
@@ -18,17 +19,17 @@
namespace __llvm_libc {
// Platform specific function which will open the directory |name|
-// and return its file descriptor. Upon failure, this function sets the errno
-// value as suitable.
-int platform_opendir(const char *name);
+// and return its file descriptor. Upon failure, the error value is returned.
+ErrorOr<int> platform_opendir(const char *name);
// Platform specific function which will close the directory with
-// file descriptor |fd|. Returns true on success, false on failure.
-bool platform_closedir(int fd);
+// file descriptor |fd|. Returns 0 on success, or the error number on failure.
+int platform_closedir(int fd);
// Platform specific function which will fetch dirents in to buffer.
-// Returns the number of bytes written into buffer
-size_t platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer);
+// Returns the number of bytes written into buffer or the error number on
+// failure.
+ErrorOr<size_t> platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer);
// This class is designed to allow implementation of the POSIX dirent.h API.
// By itself, it is platform independent but calls platform specific
@@ -46,20 +47,26 @@ class Dir {
Mutex mutex;
-public:
// A directory is to be opened by the static method open and closed
// by the close method. So, all constructors and destructor are declared
- // as deleted.
+ // as private. Inappropriate constructors are declared as deleted.
Dir() = delete;
Dir(const Dir &) = delete;
- ~Dir() = delete;
+
+ explicit Dir(int fdesc)
+ : fd(fdesc), readptr(0), fillsize(0), mutex(false, false, false) {}
+ ~Dir() = default;
Dir &operator=(const Dir &) = delete;
- static Dir *open(const char *path);
+public:
+ static ErrorOr<Dir *> open(const char *path);
- struct ::dirent *read();
+ ErrorOr<struct ::dirent *> read();
+ // Returns 0 on success or the error number on failure. If an error number
+ // was returned, then the resources associated with the directory are not
+ // cleaned up.
int close();
int getfd() { return fd; }
diff --git a/libc/src/__support/File/linux_dir.cpp b/libc/src/__support/File/linux_dir.cpp
index 82274e1..86aaaae 100644
--- a/libc/src/__support/File/linux_dir.cpp
+++ b/libc/src/__support/File/linux_dir.cpp
@@ -9,14 +9,14 @@
#include "dir.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/error_or.h"
-#include <errno.h>
#include <fcntl.h> // For open flags
#include <sys/syscall.h> // For syscall numbers
namespace __llvm_libc {
-int platform_opendir(const char *name) {
+ErrorOr<int> platform_opendir(const char *name) {
int open_flags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
#ifdef SYS_open
int fd = __llvm_libc::syscall_impl(SYS_open, name, open_flags);
@@ -28,29 +28,26 @@ int platform_opendir(const char *name) {
#endif
if (fd < 0) {
- errno = -fd;
- return -1;
+ return __llvm_libc::Error(-fd);
}
return fd;
}
-size_t platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer) {
+ErrorOr<size_t> platform_fetch_dirents(int fd, cpp::span<uint8_t> buffer) {
long size =
__llvm_libc::syscall_impl(SYS_getdents, fd, buffer.data(), buffer.size());
if (size < 0) {
- errno = -size;
- return 0;
+ return __llvm_libc::Error(static_cast<int>(-size));
}
return size;
}
-bool platform_closedir(int fd) {
+int platform_closedir(int fd) {
long ret = __llvm_libc::syscall_impl(SYS_close, fd);
if (ret < 0) {
- errno = -ret;
- return false;
+ return static_cast<int>(-ret);
}
- return true;
+ return 0;
}
} // namespace __llvm_libc
diff --git a/libc/src/dirent/CMakeLists.txt b/libc/src/dirent/CMakeLists.txt
index e4227a6..eb41846 100644
--- a/libc/src/dirent/CMakeLists.txt
+++ b/libc/src/dirent/CMakeLists.txt
@@ -8,6 +8,7 @@ add_entrypoint_object(
libc.include.dirent
libc.src.__support.File.dir
libc.src.__support.File.platform_dir
+ libc.src.errno.errno
)
add_entrypoint_object(
@@ -32,6 +33,7 @@ add_entrypoint_object(
libc.include.dirent
libc.src.__support.File.dir
libc.src.__support.File.platform_dir
+ libc.src.errno.errno
)
add_entrypoint_object(
@@ -44,4 +46,5 @@ add_entrypoint_object(
libc.include.dirent
libc.src.__support.File.dir
libc.src.__support.File.platform_dir
+ libc.src.errno.errno
)
diff --git a/libc/src/dirent/closedir.cpp b/libc/src/dirent/closedir.cpp
index f4925db..39dfc0c 100644
--- a/libc/src/dirent/closedir.cpp
+++ b/libc/src/dirent/closedir.cpp
@@ -12,12 +12,18 @@
#include "src/__support/common.h"
#include <dirent.h>
+#include <errno.h>
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(int, closedir, (::DIR * dir)) {
auto *d = reinterpret_cast<__llvm_libc::Dir *>(dir);
- return d->close();
+ int retval = d->close();
+ if (retval != 0) {
+ errno = retval;
+ return -1;
+ }
+ return 0;
}
} // namespace __llvm_libc
diff --git a/libc/src/dirent/opendir.cpp b/libc/src/dirent/opendir.cpp
index 0222944..cf5ee18 100644
--- a/libc/src/dirent/opendir.cpp
+++ b/libc/src/dirent/opendir.cpp
@@ -12,11 +12,17 @@
#include "src/__support/common.h"
#include <dirent.h>
+#include <errno.h>
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(::DIR *, opendir, (const char *name)) {
- return reinterpret_cast<::DIR *>(Dir::open(name));
+ auto dir = Dir::open(name);
+ if (!dir) {
+ errno = dir.error();
+ return nullptr;
+ }
+ return reinterpret_cast<DIR *>(dir.value());
}
} // namespace __llvm_libc
diff --git a/libc/src/dirent/readdir.cpp b/libc/src/dirent/readdir.cpp
index 9689850..b9ce301 100644
--- a/libc/src/dirent/readdir.cpp
+++ b/libc/src/dirent/readdir.cpp
@@ -12,12 +12,18 @@
#include "src/__support/common.h"
#include <dirent.h>
+#include <errno.h>
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(struct ::dirent *, readdir, (::DIR * dir)) {
auto *d = reinterpret_cast<__llvm_libc::Dir *>(dir);
- return d->read();
+ auto dirent_val = d->read();
+ if (!dirent_val) {
+ errno = dirent_val.error();
+ return nullptr;
+ }
+ return dirent_val;
}
} // namespace __llvm_libc