diff options
author | NAKAMURA Takumi <geek4civic@gmail.com> | 2025-01-09 17:16:04 +0900 |
---|---|---|
committer | NAKAMURA Takumi <geek4civic@gmail.com> | 2025-01-09 17:16:04 +0900 |
commit | 0aa930a41f2d1ebf1fa90ec42da8f96d15a4dcbb (patch) | |
tree | 6a77b463f700e090df586672c26b9fe765fd115b /libcxx/src | |
parent | ec6892d1c979ce0b84c86918d5cdbb03037b409a (diff) | |
parent | 6d16b1c5c468a79ecf867293023c89ac518ecdda (diff) | |
download | llvm-users/chapuni/cov/single/nextcount-base.zip llvm-users/chapuni/cov/single/nextcount-base.tar.gz llvm-users/chapuni/cov/single/nextcount-base.tar.bz2 |
Merge branch 'users/chapuni/cov/single/pair' into users/chapuni/cov/single/nextcount-baseusers/chapuni/cov/single/nextcount-base
Diffstat (limited to 'libcxx/src')
-rw-r--r-- | libcxx/src/experimental/tzdb.cpp | 3 | ||||
-rw-r--r-- | libcxx/src/filesystem/directory_iterator.cpp | 10 | ||||
-rw-r--r-- | libcxx/src/filesystem/error.h | 73 | ||||
-rw-r--r-- | libcxx/src/filesystem/file_descriptor.h | 12 | ||||
-rw-r--r-- | libcxx/src/filesystem/operations.cpp | 235 | ||||
-rw-r--r-- | libcxx/src/filesystem/posix_compat.h | 73 | ||||
-rw-r--r-- | libcxx/src/include/overridable_function.h | 115 | ||||
-rw-r--r-- | libcxx/src/new.cpp | 22 | ||||
-rw-r--r-- | libcxx/src/print.cpp | 2 | ||||
-rw-r--r-- | libcxx/src/system_error.cpp | 159 |
10 files changed, 442 insertions, 262 deletions
diff --git a/libcxx/src/experimental/tzdb.cpp b/libcxx/src/experimental/tzdb.cpp index d22de21..638d45f 100644 --- a/libcxx/src/experimental/tzdb.cpp +++ b/libcxx/src/experimental/tzdb.cpp @@ -9,11 +9,14 @@ // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html #include <algorithm> +#include <cctype> #include <chrono> #include <filesystem> #include <fstream> #include <stdexcept> #include <string> +#include <string_view> +#include <vector> #include "include/tzdb/time_zone_private.h" #include "include/tzdb/types_private.h" diff --git a/libcxx/src/filesystem/directory_iterator.cpp b/libcxx/src/filesystem/directory_iterator.cpp index d7ed9a3..7e8e40d 100644 --- a/libcxx/src/filesystem/directory_iterator.cpp +++ b/libcxx/src/filesystem/directory_iterator.cpp @@ -47,9 +47,9 @@ public: } __stream_ = ::FindFirstFileW((root / "*").c_str(), &__data_); if (__stream_ == INVALID_HANDLE_VALUE) { - ec = detail::make_windows_error(GetLastError()); + ec = detail::get_last_error(); const bool ignore_permission_denied = bool(opts & directory_options::skip_permission_denied); - if (ignore_permission_denied && ec.value() == static_cast<int>(errc::permission_denied)) + if (ignore_permission_denied && ec == errc::permission_denied) ec.clear(); return; } @@ -91,7 +91,7 @@ private: error_code close() noexcept { error_code ec; if (!::FindClose(__stream_)) - ec = detail::make_windows_error(GetLastError()); + ec = detail::get_last_error(); __stream_ = INVALID_HANDLE_VALUE; return ec; } @@ -118,7 +118,7 @@ public: if ((__stream_ = ::opendir(root.c_str())) == nullptr) { ec = detail::capture_errno(); const bool allow_eacces = bool(opts & directory_options::skip_permission_denied); - if (allow_eacces && ec.value() == EACCES) + if (allow_eacces && ec == errc::permission_denied) ec.clear(); return; } @@ -307,7 +307,7 @@ bool recursive_directory_iterator::__try_recursion(error_code* ec) { } if (m_ec) { const bool allow_eacess = bool(__imp_->__options_ & directory_options::skip_permission_denied); - if (m_ec.value() == EACCES && allow_eacess) { + if (m_ec == errc::permission_denied && allow_eacess) { if (ec) ec->clear(); } else { diff --git a/libcxx/src/filesystem/error.h b/libcxx/src/filesystem/error.h index 07ba7fc..c021391 100644 --- a/libcxx/src/filesystem/error.h +++ b/libcxx/src/filesystem/error.h @@ -32,80 +32,21 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM namespace detail { -#if defined(_LIBCPP_WIN32API) - -inline errc __win_err_to_errc(int err) { - constexpr struct { - DWORD win; - errc errc; - } win_error_mapping[] = { - {ERROR_ACCESS_DENIED, errc::permission_denied}, - {ERROR_ALREADY_EXISTS, errc::file_exists}, - {ERROR_BAD_NETPATH, errc::no_such_file_or_directory}, - {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory}, - {ERROR_BAD_UNIT, errc::no_such_device}, - {ERROR_BROKEN_PIPE, errc::broken_pipe}, - {ERROR_BUFFER_OVERFLOW, errc::filename_too_long}, - {ERROR_BUSY, errc::device_or_resource_busy}, - {ERROR_BUSY_DRIVE, errc::device_or_resource_busy}, - {ERROR_CANNOT_MAKE, errc::permission_denied}, - {ERROR_CANTOPEN, errc::io_error}, - {ERROR_CANTREAD, errc::io_error}, - {ERROR_CANTWRITE, errc::io_error}, - {ERROR_CURRENT_DIRECTORY, errc::permission_denied}, - {ERROR_DEV_NOT_EXIST, errc::no_such_device}, - {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy}, - {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty}, - {ERROR_DIRECTORY, errc::invalid_argument}, - {ERROR_DISK_FULL, errc::no_space_on_device}, - {ERROR_FILE_EXISTS, errc::file_exists}, - {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory}, - {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device}, - {ERROR_INVALID_ACCESS, errc::permission_denied}, - {ERROR_INVALID_DRIVE, errc::no_such_device}, - {ERROR_INVALID_FUNCTION, errc::function_not_supported}, - {ERROR_INVALID_HANDLE, errc::invalid_argument}, - {ERROR_INVALID_NAME, errc::no_such_file_or_directory}, - {ERROR_INVALID_PARAMETER, errc::invalid_argument}, - {ERROR_LOCK_VIOLATION, errc::no_lock_available}, - {ERROR_LOCKED, errc::no_lock_available}, - {ERROR_NEGATIVE_SEEK, errc::invalid_argument}, - {ERROR_NOACCESS, errc::permission_denied}, - {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory}, - {ERROR_NOT_READY, errc::resource_unavailable_try_again}, - {ERROR_NOT_SAME_DEVICE, errc::cross_device_link}, - {ERROR_NOT_SUPPORTED, errc::not_supported}, - {ERROR_OPEN_FAILED, errc::io_error}, - {ERROR_OPEN_FILES, errc::device_or_resource_busy}, - {ERROR_OPERATION_ABORTED, errc::operation_canceled}, - {ERROR_OUTOFMEMORY, errc::not_enough_memory}, - {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory}, - {ERROR_READ_FAULT, errc::io_error}, - {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument}, - {ERROR_RETRY, errc::resource_unavailable_try_again}, - {ERROR_SEEK, errc::io_error}, - {ERROR_SHARING_VIOLATION, errc::permission_denied}, - {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open}, - {ERROR_WRITE_FAULT, errc::io_error}, - {ERROR_WRITE_PROTECT, errc::permission_denied}, - }; - - for (const auto& pair : win_error_mapping) - if (pair.win == static_cast<DWORD>(err)) - return pair.errc; - return errc::invalid_argument; -} - -#endif // _LIBCPP_WIN32API +// On windows, libc functions use errno, but system functions use GetLastError. +// So, callers need to be careful which of these next functions they call! inline error_code capture_errno() { _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero"); return error_code(errno, generic_category()); } +inline error_code get_last_error() { #if defined(_LIBCPP_WIN32API) -inline error_code make_windows_error(int err) { return make_error_code(__win_err_to_errc(err)); } + return std::error_code(GetLastError(), std::system_category()); +#else + return capture_errno(); #endif +} template <class T> T error_value(); diff --git a/libcxx/src/filesystem/file_descriptor.h b/libcxx/src/filesystem/file_descriptor.h index db66ad5..9c279c4 100644 --- a/libcxx/src/filesystem/file_descriptor.h +++ b/libcxx/src/filesystem/file_descriptor.h @@ -201,7 +201,7 @@ inline perms posix_get_perms(const StatT& st) noexcept { return static_cast<perm inline file_status create_file_status(error_code& m_ec, path const& p, const StatT& path_stat, error_code* ec) { if (ec) *ec = m_ec; - if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { + if (m_ec && (m_ec == errc::no_such_file_or_directory || m_ec == errc::not_a_directory)) { return file_status(file_type::not_found); } else if (m_ec) { ErrorHandler<void> err("posix_stat", ec, &p); @@ -236,7 +236,7 @@ inline file_status create_file_status(error_code& m_ec, path const& p, const Sta inline file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) { error_code m_ec; if (detail::stat(p.c_str(), &path_stat) == -1) - m_ec = detail::capture_errno(); + m_ec = detail::get_last_error(); return create_file_status(m_ec, p, path_stat, ec); } @@ -248,7 +248,7 @@ inline file_status posix_stat(path const& p, error_code* ec) { inline file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) { error_code m_ec; if (detail::lstat(p.c_str(), &path_stat) == -1) - m_ec = detail::capture_errno(); + m_ec = detail::get_last_error(); return create_file_status(m_ec, p, path_stat, ec); } @@ -260,7 +260,7 @@ inline file_status posix_lstat(path const& p, error_code* ec) { // http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html inline bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) { if (detail::ftruncate(fd.fd, to_size) == -1) { - ec = capture_errno(); + ec = get_last_error(); return true; } ec.clear(); @@ -269,7 +269,7 @@ inline bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& inline bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) { if (detail::fchmod(fd.fd, st.st_mode) == -1) { - ec = capture_errno(); + ec = get_last_error(); return true; } ec.clear(); @@ -286,7 +286,7 @@ inline file_status FileDescriptor::refresh_status(error_code& ec) { m_stat = {}; error_code m_ec; if (detail::fstat(fd, &m_stat) == -1) - m_ec = capture_errno(); + m_ec = get_last_error(); m_status = create_file_status(m_ec, name, m_stat, &ec); return m_status; } diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp index d771f20..23c1c28 100644 --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -15,6 +15,7 @@ #include <filesystem> #include <iterator> #include <string_view> +#include <system_error> #include <type_traits> #include <vector> @@ -32,11 +33,24 @@ # include <dirent.h> # include <sys/stat.h> # include <sys/statvfs.h> +# include <sys/types.h> # include <unistd.h> #endif #include <fcntl.h> /* values for fchmodat */ #include <time.h> +// since Linux 4.5 and FreeBSD 13, but the Linux libc wrapper is only provided by glibc >= 2.27 and musl +#if defined(__linux__) +# if defined(_LIBCPP_GLIBC_PREREQ) +# if _LIBCPP_GLIBC_PREREQ(2, 27) +# define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE +# endif +# elif _LIBCPP_HAS_MUSL_LIBC +# define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE +# endif +#elif defined(__FreeBSD__) +# define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE +#endif #if __has_include(<sys/sendfile.h>) # include <sys/sendfile.h> # define _LIBCPP_FILESYSTEM_USE_SENDFILE @@ -44,10 +58,18 @@ # include <copyfile.h> # define _LIBCPP_FILESYSTEM_USE_COPYFILE #else -# include <fstream> # define _LIBCPP_FILESYSTEM_USE_FSTREAM #endif +// sendfile and copy_file_range need to fall back +// to the fstream implementation for special files +#if (defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) || defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) || \ + defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)) && \ + _LIBCPP_HAS_LOCALIZATION +# include <fstream> +# define _LIBCPP_FILESYSTEM_NEED_FSTREAM +#endif + #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB) # pragma comment(lib, "rt") #endif @@ -86,7 +108,7 @@ path __canonical(path const& orig_p, error_code* ec) { #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API) std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free); if (hold.get() == nullptr) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); return {hold.get()}; #else # if defined(__MVS__) && !defined(PATH_MAX) @@ -96,7 +118,7 @@ path __canonical(path const& orig_p, error_code* ec) { # endif path::value_type* ret; if ((ret = detail::realpath(p.c_str(), buff)) == nullptr) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); return {ret}; #endif } @@ -178,9 +200,89 @@ void __copy(const path& from, const path& to, copy_options options, error_code* namespace detail { namespace { +#if defined(_LIBCPP_FILESYSTEM_NEED_FSTREAM) +bool copy_file_impl_fstream(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { + ifstream in; + in.__open(read_fd.fd, ios::binary); + if (!in.is_open()) { + // This assumes that __open didn't reset the error code. + ec = capture_errno(); + return false; + } + read_fd.fd = -1; + ofstream out; + out.__open(write_fd.fd, ios::binary); + if (!out.is_open()) { + ec = capture_errno(); + return false; + } + write_fd.fd = -1; + + if (in.good() && out.good()) { + using InIt = istreambuf_iterator<char>; + using OutIt = ostreambuf_iterator<char>; + InIt bin(in); + InIt ein; + OutIt bout(out); + copy(bin, ein, bout); + } + if (out.fail() || in.fail()) { + ec = make_error_code(errc::io_error); + return false; + } + + ec.clear(); + return true; +} +#endif + +#if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) +bool copy_file_impl_copy_file_range(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { + size_t count = read_fd.get_stat().st_size; + // a zero-length file is either empty, or not copyable by this syscall + // return early to avoid the syscall cost + if (count == 0) { + ec = {EINVAL, generic_category()}; + return false; + } + // do not modify the fd positions as copy_file_impl_sendfile may be called after a partial copy +# if defined(__linux__) + loff_t off_in = 0; + loff_t off_out = 0; +# else + off_t off_in = 0; + off_t off_out = 0; +# endif + + do { + ssize_t res; + + if ((res = ::copy_file_range(read_fd.fd, &off_in, write_fd.fd, &off_out, count, 0)) == -1) { + ec = capture_errno(); + return false; + } + count -= res; + } while (count > 0); + + ec.clear(); + + return true; +} +#endif + #if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) -bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { +bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { size_t count = read_fd.get_stat().st_size; + // a zero-length file is either empty, or not copyable by this syscall + // return early to avoid the syscall cost + // however, we can't afford this luxury in the no-locale build, + // as we can't utilize the fstream impl to copy empty files +# if _LIBCPP_HAS_LOCALIZATION + if (count == 0) { + ec = {EINVAL, generic_category()}; + return false; + } +# endif do { ssize_t res; if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) { @@ -194,6 +296,54 @@ bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_cod return true; } +#endif + +#if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) || defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) +// If we have copy_file_range or sendfile, try both in succession (if available). +// If both fail, fall back to using fstream. +bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { +# if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) + if (copy_file_impl_copy_file_range(read_fd, write_fd, ec)) { + return true; + } + // EINVAL: src and dst are the same file (this is not cheaply + // detectable from userspace) + // EINVAL: copy_file_range is unsupported for this file type by the + // underlying filesystem + // ENOTSUP: undocumented, can arise with old kernels and NFS + // EOPNOTSUPP: filesystem does not implement copy_file_range + // ETXTBSY: src or dst is an active swapfile (nonsensical, but allowed + // with normal copying) + // EXDEV: src and dst are on different filesystems that do not support + // cross-fs copy_file_range + // ENOENT: undocumented, can arise with CIFS + // ENOSYS: unsupported by kernel or blocked by seccomp + if (ec.value() != EINVAL && ec.value() != ENOTSUP && ec.value() != EOPNOTSUPP && ec.value() != ETXTBSY && + ec.value() != EXDEV && ec.value() != ENOENT && ec.value() != ENOSYS) { + return false; + } + ec.clear(); +# endif + +# if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) + if (copy_file_impl_sendfile(read_fd, write_fd, ec)) { + return true; + } + // EINVAL: unsupported file type + if (ec.value() != EINVAL) { + return false; + } + ec.clear(); +# endif + +# if defined(_LIBCPP_FILESYSTEM_NEED_FSTREAM) + return copy_file_impl_fstream(read_fd, write_fd, ec); +# else + // since iostreams are unavailable in the no-locale build, just fail after a failed sendfile + ec.assign(EINVAL, std::system_category()); + return false; +# endif +} #elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE) bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { struct CopyFileState { @@ -217,37 +367,7 @@ bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_cod } #elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM) bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) { - ifstream in; - in.__open(read_fd.fd, ios::binary); - if (!in.is_open()) { - // This assumes that __open didn't reset the error code. - ec = capture_errno(); - return false; - } - read_fd.fd = -1; - ofstream out; - out.__open(write_fd.fd, ios::binary); - if (!out.is_open()) { - ec = capture_errno(); - return false; - } - write_fd.fd = -1; - - if (in.good() && out.good()) { - using InIt = istreambuf_iterator<char>; - using OutIt = ostreambuf_iterator<char>; - InIt bin(in); - InIt ein; - OutIt bout(out); - copy(bin, ein, bout); - } - if (out.fail() || in.fail()) { - ec = make_error_code(errc::io_error); - return false; - } - - ec.clear(); - return true; + return copy_file_impl_fstream(read_fd, write_fd, ec); } #else # error "Unknown implementation for copy_file_impl" @@ -393,9 +513,9 @@ bool __create_directory(const path& p, error_code* ec) { if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0) return true; - if (errno != EEXIST) - return err.report(capture_errno()); - error_code mec = capture_errno(); + error_code mec = detail::get_last_error(); + if (mec != errc::file_exists) + return err.report(mec); error_code ignored_ec; const file_status st = status(p, ignored_ec); if (!is_directory(st)) @@ -417,10 +537,10 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) { if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0) return true; - if (errno != EEXIST) - return err.report(capture_errno()); + mec = detail::get_last_error(); + if (mec != errc::file_exists) + return err.report(mec); - mec = capture_errno(); error_code ignored_ec; st = status(p, ignored_ec); if (!is_directory(st)) @@ -431,19 +551,19 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) { void __create_directory_symlink(path const& from, path const& to, error_code* ec) { ErrorHandler<void> err("create_directory_symlink", ec, &from, &to); if (detail::symlink_dir(from.c_str(), to.c_str()) == -1) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); } void __create_hard_link(const path& from, const path& to, error_code* ec) { ErrorHandler<void> err("create_hard_link", ec, &from, &to); if (detail::link(from.c_str(), to.c_str()) == -1) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); } void __create_symlink(path const& from, path const& to, error_code* ec) { ErrorHandler<void> err("create_symlink", ec, &from, &to); if (detail::symlink_file(from.c_str(), to.c_str()) == -1) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); } path __current_path(error_code* ec) { @@ -486,7 +606,7 @@ path __current_path(error_code* ec) { unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size), deleter); if (hold.get() == nullptr) - return err.report(capture_errno(), "call to getcwd failed"); + return err.report(detail::get_last_error(), "call to getcwd failed"); return {hold.get()}; } @@ -494,7 +614,7 @@ path __current_path(error_code* ec) { void __current_path(const path& p, error_code* ec) { ErrorHandler<void> err("current_path", ec, &p); if (detail::chdir(p.c_str()) == -1) - err.report(capture_errno()); + err.report(detail::get_last_error()); } bool __equivalent(const path& p1, const path& p2, error_code* ec) { @@ -582,10 +702,10 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { return err.report(errc::value_too_large); detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0); if (!h) - return err.report(detail::make_windows_error(GetLastError())); + return err.report(detail::get_last_error()); FILETIME last_write = timespec_to_filetime(ts); if (!SetFileTime(h, nullptr, nullptr, &last_write)) - return err.report(detail::make_windows_error(GetLastError())); + return err.report(detail::get_last_error()); #else error_code m_ec; array<TimeSpec, 2> tbuf; @@ -643,7 +763,7 @@ void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { - return err.report(capture_errno()); + return err.report(detail::get_last_error()); } #else if (set_sym_perms) @@ -671,14 +791,14 @@ path __read_symlink(const path& p, error_code* ec) { #else StatT sb; if (detail::lstat(p.c_str(), &sb) == -1) { - return err.report(capture_errno()); + return err.report(detail::get_last_error()); } const size_t size = sb.st_size + 1; auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]); #endif detail::SSizeT ret; if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); // Note that `ret` returning `0` would work, resulting in a valid empty string being returned. if (static_cast<size_t>(ret) >= size) return err.report(errc::value_too_large); @@ -689,8 +809,9 @@ path __read_symlink(const path& p, error_code* ec) { bool __remove(const path& p, error_code* ec) { ErrorHandler<bool> err("remove", ec, &p); if (detail::remove(p.c_str()) == -1) { - if (errno != ENOENT) - err.report(capture_errno()); + error_code mec = detail::get_last_error(); + if (mec != errc::no_such_file_or_directory) + err.report(mec); return false; } return true; @@ -843,13 +964,13 @@ uintmax_t __remove_all(const path& p, error_code* ec) { void __rename(const path& from, const path& to, error_code* ec) { ErrorHandler<void> err("rename", ec, &from, &to); if (detail::rename(from.c_str(), to.c_str()) == -1) - err.report(capture_errno()); + err.report(detail::get_last_error()); } void __resize_file(const path& p, uintmax_t size, error_code* ec) { ErrorHandler<void> err("resize_file", ec, &p); if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1) - return err.report(capture_errno()); + return err.report(detail::get_last_error()); } space_info __space(const path& p, error_code* ec) { @@ -857,7 +978,7 @@ space_info __space(const path& p, error_code* ec) { space_info si; detail::StatVFS m_svfs = {}; if (detail::statvfs(p.c_str(), &m_svfs) == -1) { - err.report(capture_errno()); + err.report(detail::get_last_error()); si.capacity = si.free = si.available = static_cast<uintmax_t>(-1); return si; } @@ -884,7 +1005,7 @@ path __temp_directory_path(error_code* ec) { wchar_t buf[MAX_PATH]; DWORD retval = GetTempPathW(MAX_PATH, buf); if (!retval) - return err.report(detail::make_windows_error(GetLastError())); + return err.report(detail::get_last_error()); if (retval > MAX_PATH) return err.report(errc::filename_too_long); // GetTempPathW returns a path with a trailing slash, which we diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h index b41c004..ddd99d8 100644 --- a/libcxx/src/filesystem/posix_compat.h +++ b/libcxx/src/filesystem/posix_compat.h @@ -11,9 +11,10 @@ // // These generally behave like the proper posix functions, with these // exceptions: -// On Windows, they take paths in wchar_t* form, instead of char* form. -// The symlink() function is split into two frontends, symlink_file() -// and symlink_dir(). +// - On Windows, they take paths in wchar_t* form, instead of char* form. +// - The symlink() function is split into two frontends, symlink_file() +// and symlink_dir(). +// - Errors should be retrieved with get_last_error, not errno. // // These are provided within an anonymous namespace within the detail // namespace - callers need to include this header and call them as @@ -122,11 +123,6 @@ namespace detail { # define O_NONBLOCK 0 -inline int set_errno(int e = GetLastError()) { - errno = static_cast<int>(__win_err_to_errc(e)); - return -1; -} - class WinHandle { public: WinHandle(const wchar_t* p, DWORD access, DWORD flags) { @@ -153,7 +149,7 @@ private: inline int stat_handle(HANDLE h, StatT* buf) { FILE_BASIC_INFO basic; if (!GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic))) - return set_errno(); + return -1; memset(buf, 0, sizeof(*buf)); buf->st_mtim = filetime_to_timespec(basic.LastWriteTime); buf->st_atim = filetime_to_timespec(basic.LastAccessTime); @@ -168,18 +164,18 @@ inline int stat_handle(HANDLE h, StatT* buf) { if (basic.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { FILE_ATTRIBUTE_TAG_INFO tag; if (!GetFileInformationByHandleEx(h, FileAttributeTagInfo, &tag, sizeof(tag))) - return set_errno(); + return -1; if (tag.ReparseTag == IO_REPARSE_TAG_SYMLINK) buf->st_mode = (buf->st_mode & ~_S_IFMT) | _S_IFLNK; } FILE_STANDARD_INFO standard; if (!GetFileInformationByHandleEx(h, FileStandardInfo, &standard, sizeof(standard))) - return set_errno(); + return -1; buf->st_nlink = standard.NumberOfLinks; buf->st_size = standard.EndOfFile.QuadPart; BY_HANDLE_FILE_INFORMATION info; if (!GetFileInformationByHandle(h, &info)) - return set_errno(); + return -1; buf->st_dev = info.dwVolumeSerialNumber; memcpy(&buf->st_ino.id[0], &info.nFileIndexHigh, 4); memcpy(&buf->st_ino.id[4], &info.nFileIndexLow, 4); @@ -189,7 +185,7 @@ inline int stat_handle(HANDLE h, StatT* buf) { inline int stat_file(const wchar_t* path, StatT* buf, DWORD flags) { WinHandle h(path, FILE_READ_ATTRIBUTES, flags); if (!h) - return set_errno(); + return -1; int ret = stat_handle(h, buf); return ret; } @@ -206,7 +202,7 @@ inline int fstat(int fd, StatT* buf) { inline int mkdir(const wchar_t* path, int permissions) { (void)permissions; if (!CreateDirectoryW(path, nullptr)) - return set_errno(); + return -1; return 0; } @@ -219,10 +215,10 @@ inline int symlink_file_dir(const wchar_t* oldname, const wchar_t* newname, bool return 0; int e = GetLastError(); if (e != ERROR_INVALID_PARAMETER) - return set_errno(e); + return -1; if (CreateSymbolicLinkW(newname, oldname, flags)) return 0; - return set_errno(); + return -1; } inline int symlink_file(const wchar_t* oldname, const wchar_t* newname) { @@ -236,17 +232,17 @@ inline int symlink_dir(const wchar_t* oldname, const wchar_t* newname) { inline int link(const wchar_t* oldname, const wchar_t* newname) { if (CreateHardLinkW(newname, oldname, nullptr)) return 0; - return set_errno(); + return -1; } inline int remove(const wchar_t* path) { detail::WinHandle h(path, DELETE, FILE_FLAG_OPEN_REPARSE_POINT); if (!h) - return set_errno(); + return -1; FILE_DISPOSITION_INFO info; info.DeleteFile = TRUE; if (!SetFileInformationByHandle(h, FileDispositionInfo, &info, sizeof(info))) - return set_errno(); + return -1; return 0; } @@ -254,9 +250,9 @@ inline int truncate_handle(HANDLE h, off_t length) { LARGE_INTEGER size_param; size_param.QuadPart = length; if (!SetFilePointerEx(h, size_param, 0, FILE_BEGIN)) - return set_errno(); + return -1; if (!SetEndOfFile(h)) - return set_errno(); + return -1; return 0; } @@ -268,19 +264,19 @@ inline int ftruncate(int fd, off_t length) { inline int truncate(const wchar_t* path, off_t length) { detail::WinHandle h(path, GENERIC_WRITE, 0); if (!h) - return set_errno(); + return -1; return truncate_handle(h, length); } inline int rename(const wchar_t* from, const wchar_t* to) { if (!(MoveFileExW(from, to, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))) - return set_errno(); + return -1; return 0; } inline int chdir(const wchar_t* path) { if (!SetCurrentDirectoryW(path)) - return set_errno(); + return -1; return 0; } @@ -300,7 +296,7 @@ inline int statvfs(const wchar_t* p, StatVFS* buf) { break; path parent = dir.parent_path(); if (parent == dir) { - errno = ENOENT; + SetLastError(ERROR_PATH_NOT_FOUND); return -1; } dir = parent; @@ -308,7 +304,7 @@ inline int statvfs(const wchar_t* p, StatVFS* buf) { ULARGE_INTEGER free_bytes_available_to_caller, total_number_of_bytes, total_number_of_free_bytes; if (!GetDiskFreeSpaceExW( dir.c_str(), &free_bytes_available_to_caller, &total_number_of_bytes, &total_number_of_free_bytes)) - return set_errno(); + return -1; buf->f_frsize = 1; buf->f_blocks = total_number_of_bytes.QuadPart; buf->f_bfree = total_number_of_free_bytes.QuadPart; @@ -330,7 +326,6 @@ inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t retval = GetCurrentDirectoryW(buff_size, buff.get()); } if (!retval) { - set_errno(); return nullptr; } return buff.release(); @@ -342,7 +337,6 @@ inline wchar_t* realpath(const wchar_t* path, [[maybe_unused]] wchar_t* resolved WinHandle h(path, FILE_READ_ATTRIBUTES, 0); if (!h) { - set_errno(); return nullptr; } size_t buff_size = MAX_PATH + 10; @@ -354,7 +348,6 @@ inline wchar_t* realpath(const wchar_t* path, [[maybe_unused]] wchar_t* resolved retval = GetFinalPathNameByHandleW(h, buff.get(), buff_size, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); } if (!retval) { - set_errno(); return nullptr; } wchar_t* ptr = buff.get(); @@ -376,20 +369,20 @@ using ModeT = int; inline int fchmod_handle(HANDLE h, int perms) { FILE_BASIC_INFO basic; if (!GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic))) - return set_errno(); + return -1; DWORD orig_attributes = basic.FileAttributes; basic.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; if ((perms & 0222) == 0) basic.FileAttributes |= FILE_ATTRIBUTE_READONLY; if (basic.FileAttributes != orig_attributes && !SetFileInformationByHandle(h, FileBasicInfo, &basic, sizeof(basic))) - return set_errno(); + return -1; return 0; } inline int fchmodat(int /*fd*/, const wchar_t* path, int perms, int flag) { DWORD attributes = GetFileAttributesW(path); if (attributes == INVALID_FILE_ATTRIBUTES) - return set_errno(); + return -1; if (attributes & FILE_ATTRIBUTE_REPARSE_POINT && !(flag & AT_SYMLINK_NOFOLLOW)) { // If the file is a symlink, and we are supposed to operate on the target // of the symlink, we need to open a handle to it, without the @@ -397,7 +390,7 @@ inline int fchmodat(int /*fd*/, const wchar_t* path, int perms, int flag) { // symlink, and operate on it via the handle. detail::WinHandle h(path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 0); if (!h) - return set_errno(); + return -1; return fchmod_handle(h, perms); } else { // For a non-symlink, or if operating on the symlink itself instead of @@ -407,7 +400,7 @@ inline int fchmodat(int /*fd*/, const wchar_t* path, int perms, int flag) { if ((perms & 0222) == 0) attributes |= FILE_ATTRIBUTE_READONLY; if (attributes != orig_attributes && !SetFileAttributesW(path, attributes)) - return set_errno(); + return -1; } return 0; } @@ -424,18 +417,18 @@ inline SSizeT readlink(const wchar_t* path, wchar_t* ret_buf, size_t bufsize) { uint8_t buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; detail::WinHandle h(path, FILE_READ_ATTRIBUTES, FILE_FLAG_OPEN_REPARSE_POINT); if (!h) - return set_errno(); + return -1; DWORD out; if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf, sizeof(buf), &out, 0)) - return set_errno(); + return -1; const auto* reparse = reinterpret_cast<LIBCPP_REPARSE_DATA_BUFFER*>(buf); size_t path_buf_offset = offsetof(LIBCPP_REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]); if (out < path_buf_offset) { - errno = EINVAL; + SetLastError(ERROR_REPARSE_TAG_INVALID); return -1; } if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) { - errno = EINVAL; + SetLastError(ERROR_REPARSE_TAG_INVALID); return -1; } const auto& symlink = reparse->SymbolicLinkReparseBuffer; @@ -449,11 +442,11 @@ inline SSizeT readlink(const wchar_t* path, wchar_t* ret_buf, size_t bufsize) { } // name_offset/length are expressed in bytes, not in wchar_t if (path_buf_offset + name_offset + name_length > out) { - errno = EINVAL; + SetLastError(ERROR_REPARSE_TAG_INVALID); return -1; } if (name_length / sizeof(wchar_t) > bufsize) { - errno = ENOMEM; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); return -1; } memcpy(ret_buf, &symlink.PathBuffer[name_offset / sizeof(wchar_t)], name_length); diff --git a/libcxx/src/include/overridable_function.h b/libcxx/src/include/overridable_function.h index 6c70f62..7372e34 100644 --- a/libcxx/src/include/overridable_function.h +++ b/libcxx/src/include/overridable_function.h @@ -29,106 +29,81 @@ // This is a low-level utility which does not work on all platforms, since it needs // to make assumptions about the object file format in use. Furthermore, it requires // the "base definition" of the function (the one we want to check whether it has been -// overridden) to be annotated with the _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE macro. +// overridden) to be defined using the _LIBCPP_OVERRIDABLE_FUNCTION macro. // // This currently works with Mach-O files (used on Darwin) and with ELF files (used on Linux // and others). On platforms where we know how to implement this detection, the macro // _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION is defined to 1, and it is defined to 0 on -// other platforms. The _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE macro is defined to -// nothing on unsupported platforms so that it can be used to decorate functions regardless -// of whether detection is actually supported. +// other platforms. The _LIBCPP_OVERRIDABLE_FUNCTION macro expands to regular function +// definition on unsupported platforms so that it can be used to decorate functions +// regardless of whether detection is actually supported. // // How does this work? // ------------------- // // Let's say we want to check whether a weak function `f` has been overridden by the user. -// The general mechanism works by placing `f`'s definition (in the libc++ built library) -// inside a special section, which we do using the `__section__` attribute via the -// _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE macro. +// The general mechanism works by defining a symbol `f_impl__` and a weak alias `f` via the +// _LIBCPP_OVERRIDABLE_FUNCTION macro. // // Then, when comes the time to check whether the function has been overridden, we take -// the address of the function and we check whether it falls inside the special function -// we created. This can be done by finding pointers to the start and the end of the section -// (which is done differently for ELF and Mach-O), and then checking whether `f` falls -// within those bounds. If it falls within those bounds, then `f` is still inside the -// special section and so it is the version we defined in the libc++ built library, i.e. -// it was not overridden. Otherwise, it was overridden by the user because it falls -// outside of the section. +// the address of the function `f` and we check whether it is different from `f_impl__`. +// If so it means the function was overriden by the user. // // Important note // -------------- // -// This mechanism should never be used outside of the libc++ built library. In particular, -// attempting to use this within the libc++ headers will not work at all because we don't -// want to be defining special sections inside user's executables which use our headers. +// This mechanism should never be used outside of the libc++ built library. Functions defined +// with this macro must be defined at global scope. // #if defined(_LIBCPP_OBJECT_FORMAT_MACHO) -# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 -# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE \ - __attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions"))) - _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Ret, class... _Args> -_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept { - // Declare two dummy bytes and give them these special `__asm` values. These values are - // defined by the linker, which means that referring to `&__lcxx_override_start` will - // effectively refer to the address where the section starts (and same for the end). - extern char __lcxx_override_start __asm("section$start$__TEXT$__lcxx_override"); - extern char __lcxx_override_end __asm("section$end$__TEXT$__lcxx_override"); - - // Now get a uintptr_t out of these locations, and out of the function pointer. - uintptr_t __start = reinterpret_cast<uintptr_t>(&__lcxx_override_start); - uintptr_t __end = reinterpret_cast<uintptr_t>(&__lcxx_override_end); - uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr); - -# if __has_feature(ptrauth_calls) - // We must pass a void* to ptrauth_strip since it only accepts a pointer type. Also, in particular, - // we must NOT pass a function pointer, otherwise we will strip the function pointer, and then attempt - // to authenticate and re-sign it when casting it to a uintptr_t again, which will fail because we just - // stripped the function pointer. See rdar://122927845. - __ptr = reinterpret_cast<uintptr_t>(ptrauth_strip(reinterpret_cast<void*>(__ptr), ptrauth_key_function_pointer)); -# endif - - // Finally, the function was overridden if it falls outside of the section's bounds. - return __ptr < __start || __ptr > __end; -} -_LIBCPP_END_NAMESPACE_STD -// The NVPTX linker cannot create '__start/__stop' sections. -#elif defined(_LIBCPP_OBJECT_FORMAT_ELF) && !defined(__NVPTX__) +template <auto _Func> +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_function_overridden(); -# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 -# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE __attribute__((__section__("__lcxx_override"))) +_LIBCPP_END_NAMESPACE_STD -// This is very similar to what we do for Mach-O above. The ELF linker will implicitly define -// variables with those names corresponding to the start and the end of the section. -// -// See https://stackoverflow.com/questions/16552710/how-do-you-get-the-start-and-end-addresses-of-a-custom-elf-section -extern char __start___lcxx_override; -extern char __stop___lcxx_override; +# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 +# define _LIBCPP_OVERRIDABLE_FUNCTION(symbol, type, name, arglist) \ + static __attribute__((used)) type symbol##_impl__ arglist __asm__("_" _LIBCPP_TOSTRING(symbol)); \ + __asm__(".globl _" _LIBCPP_TOSTRING(symbol)); \ + __asm__(".weak_definition _" _LIBCPP_TOSTRING(symbol)); \ + extern __typeof(symbol##_impl__) name __attribute__((weak_import)); \ + _LIBCPP_BEGIN_NAMESPACE_STD \ + template <> \ + inline bool __is_function_overridden<static_cast<type(*) arglist>(name)>() { \ + return static_cast<type(*) arglist>(name) != symbol##_impl__; \ + } \ + _LIBCPP_END_NAMESPACE_STD \ + static type symbol##_impl__ arglist + +#elif defined(_LIBCPP_OBJECT_FORMAT_ELF) _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Ret, class... _Args> -_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept { - uintptr_t __start = reinterpret_cast<uintptr_t>(&__start___lcxx_override); - uintptr_t __end = reinterpret_cast<uintptr_t>(&__stop___lcxx_override); - uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr); - -# if __has_feature(ptrauth_calls) - // We must pass a void* to ptrauth_strip since it only accepts a pointer type. See full explanation above. - __ptr = reinterpret_cast<uintptr_t>(ptrauth_strip(reinterpret_cast<void*>(__ptr), ptrauth_key_function_pointer)); -# endif - - return __ptr < __start || __ptr > __end; -} + +template <auto _Func> +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_function_overridden(); + _LIBCPP_END_NAMESPACE_STD +# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 +# define _LIBCPP_OVERRIDABLE_FUNCTION(symbol, type, name, arglist) \ + static type symbol##_impl__ arglist __asm__(_LIBCPP_TOSTRING(symbol##_impl__)); \ + [[gnu::weak, gnu::alias(_LIBCPP_TOSTRING(symbol##_impl__))]] type name arglist; \ + _LIBCPP_BEGIN_NAMESPACE_STD \ + template <> \ + inline bool __is_function_overridden<static_cast<type(*) arglist>(name)>() { \ + return static_cast<type(*) arglist>(name) != symbol##_impl__; \ + } \ + _LIBCPP_END_NAMESPACE_STD \ + static type symbol##_impl__ arglist + #else # define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 0 -# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE /* nothing */ +# define _LIBCPP_OVERRIDABLE_FUNCTION(symbol, type, name, arglist) _LIBCPP_WEAK type name arglist #endif diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp index e010fe4..b14b522 100644 --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -43,7 +43,7 @@ static void* operator_new_impl(std::size_t size) { return p; } -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { +_LIBCPP_OVERRIDABLE_FUNCTION(_Znwm, void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC { void* p = operator_new_impl(size); if (p == nullptr) __throw_bad_alloc_shim(); @@ -54,7 +54,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { # if !_LIBCPP_HAS_EXCEPTIONS # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)), + !std::__is_function_overridden<static_cast<void* (*)(std::size_t)>(&operator new)>(), "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, " "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because " "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case " @@ -74,7 +74,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { # endif } -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { +_LIBCPP_OVERRIDABLE_FUNCTION(_Znam, void*, operator new[], (size_t size)) _THROW_BAD_ALLOC { return ::operator new(size); } @@ -82,7 +82,7 @@ _LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { # if !_LIBCPP_HAS_EXCEPTIONS # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])), + !std::__is_function_overridden<static_cast<void* (*)(std::size_t)>(&operator new[])>(), "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, " "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because " "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case " @@ -136,8 +136,8 @@ static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignm return p; } -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* -operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { +_LIBCPP_OVERRIDABLE_FUNCTION(_ZnwmSt11align_val_t, void*, operator new, (std::size_t size, std::align_val_t alignment)) +_THROW_BAD_ALLOC { void* p = operator_new_aligned_impl(size, alignment); if (p == nullptr) __throw_bad_alloc_shim(); @@ -148,7 +148,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s # if !_LIBCPP_HAS_EXCEPTIONS # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)), + !std::__is_function_overridden<static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)>(), "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, " "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will " @@ -168,16 +168,14 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s # endif } -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* -operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { - return ::operator new(size, alignment); -} +_LIBCPP_OVERRIDABLE_FUNCTION(_ZnamSt11align_val_t, void*, operator new[], (size_t size, std::align_val_t alignment)) +_THROW_BAD_ALLOC { return ::operator new(size, alignment); } _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { # if !_LIBCPP_HAS_EXCEPTIONS # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])), + !std::__is_function_overridden<static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])>(), "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, " "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will " diff --git a/libcxx/src/print.cpp b/libcxx/src/print.cpp index 37b1fc0..4937aaf 100644 --- a/libcxx/src/print.cpp +++ b/libcxx/src/print.cpp @@ -51,7 +51,7 @@ __write_to_windows_console([[maybe_unused]] FILE* __stream, [[maybe_unused]] wst __view.size(), nullptr, nullptr) == 0) { - __throw_system_error(filesystem::detail::make_windows_error(GetLastError()), "failed to write formatted output"); + __throw_system_error(filesystem::detail::get_last_error(), "failed to write formatted output"); } } # endif // _LIBCPP_HAS_WIDE_CHARACTERS diff --git a/libcxx/src/system_error.cpp b/libcxx/src/system_error.cpp index d555bca..d5ec730 100644 --- a/libcxx/src/system_error.cpp +++ b/libcxx/src/system_error.cpp @@ -14,6 +14,7 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <optional> #include <string.h> #include <string> #include <system_error> @@ -24,8 +25,123 @@ # include <android/api-level.h> #endif +#if defined(_LIBCPP_WIN32API) +# include <windows.h> +# include <winerror.h> +#endif + _LIBCPP_BEGIN_NAMESPACE_STD +#if defined(_LIBCPP_WIN32API) + +namespace { +std::optional<errc> __win_err_to_errc(int err) { + switch (err) { + case ERROR_ACCESS_DENIED: + return errc::permission_denied; + case ERROR_ALREADY_EXISTS: + return errc::file_exists; + case ERROR_BAD_NETPATH: + return errc::no_such_file_or_directory; + case ERROR_BAD_PATHNAME: + return errc::no_such_file_or_directory; + case ERROR_BAD_UNIT: + return errc::no_such_device; + case ERROR_BROKEN_PIPE: + return errc::broken_pipe; + case ERROR_BUFFER_OVERFLOW: + return errc::filename_too_long; + case ERROR_BUSY: + return errc::device_or_resource_busy; + case ERROR_BUSY_DRIVE: + return errc::device_or_resource_busy; + case ERROR_CANNOT_MAKE: + return errc::permission_denied; + case ERROR_CANTOPEN: + return errc::io_error; + case ERROR_CANTREAD: + return errc::io_error; + case ERROR_CANTWRITE: + return errc::io_error; + case ERROR_CURRENT_DIRECTORY: + return errc::permission_denied; + case ERROR_DEV_NOT_EXIST: + return errc::no_such_device; + case ERROR_DEVICE_IN_USE: + return errc::device_or_resource_busy; + case ERROR_DIR_NOT_EMPTY: + return errc::directory_not_empty; + case ERROR_DIRECTORY: + return errc::invalid_argument; + case ERROR_DISK_FULL: + return errc::no_space_on_device; + case ERROR_FILE_EXISTS: + return errc::file_exists; + case ERROR_FILE_NOT_FOUND: + return errc::no_such_file_or_directory; + case ERROR_HANDLE_DISK_FULL: + return errc::no_space_on_device; + case ERROR_INVALID_ACCESS: + return errc::permission_denied; + case ERROR_INVALID_DRIVE: + return errc::no_such_device; + case ERROR_INVALID_FUNCTION: + return errc::function_not_supported; + case ERROR_INVALID_HANDLE: + return errc::invalid_argument; + case ERROR_INVALID_NAME: + return errc::no_such_file_or_directory; + case ERROR_INVALID_PARAMETER: + return errc::invalid_argument; + case ERROR_LOCK_VIOLATION: + return errc::no_lock_available; + case ERROR_LOCKED: + return errc::no_lock_available; + case ERROR_NEGATIVE_SEEK: + return errc::invalid_argument; + case ERROR_NOACCESS: + return errc::permission_denied; + case ERROR_NOT_ENOUGH_MEMORY: + return errc::not_enough_memory; + case ERROR_NOT_READY: + return errc::resource_unavailable_try_again; + case ERROR_NOT_SAME_DEVICE: + return errc::cross_device_link; + case ERROR_NOT_SUPPORTED: + return errc::not_supported; + case ERROR_OPEN_FAILED: + return errc::io_error; + case ERROR_OPEN_FILES: + return errc::device_or_resource_busy; + case ERROR_OPERATION_ABORTED: + return errc::operation_canceled; + case ERROR_OUTOFMEMORY: + return errc::not_enough_memory; + case ERROR_PATH_NOT_FOUND: + return errc::no_such_file_or_directory; + case ERROR_READ_FAULT: + return errc::io_error; + case ERROR_REPARSE_TAG_INVALID: + return errc::invalid_argument; + case ERROR_RETRY: + return errc::resource_unavailable_try_again; + case ERROR_SEEK: + return errc::io_error; + case ERROR_SHARING_VIOLATION: + return errc::permission_denied; + case ERROR_TOO_MANY_OPEN_FILES: + return errc::too_many_files_open; + case ERROR_WRITE_FAULT: + return errc::io_error; + case ERROR_WRITE_PROTECT: + return errc::permission_denied; + default: + return {}; + } +} +} // namespace +#endif + namespace { #if _LIBCPP_HAS_THREADS @@ -157,19 +273,52 @@ public: const char* __system_error_category::name() const noexcept { return "system"; } string __system_error_category::message(int ev) const { -#ifdef _LIBCPP_ELAST +#ifdef _LIBCPP_WIN32API + std::string result; + char* str = nullptr; + unsigned long num_chars = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + ev, + 0, + reinterpret_cast<char*>(&str), + 0, + nullptr); + auto is_whitespace = [](char ch) { return ch == '\n' || ch == '\r' || ch == ' '; }; + while (num_chars > 0 && is_whitespace(str[num_chars - 1])) + --num_chars; + + if (num_chars) + result = std::string(str, num_chars); + else + result = "Unknown error"; + + LocalFree(str); + return result; +#else +# ifdef _LIBCPP_ELAST if (ev > _LIBCPP_ELAST) return string("unspecified system_category error"); -#endif // _LIBCPP_ELAST +# endif // _LIBCPP_ELAST return __do_message::message(ev); +#endif } error_condition __system_error_category::default_error_condition(int ev) const noexcept { -#ifdef _LIBCPP_ELAST +#ifdef _LIBCPP_WIN32API + // Remap windows error codes to generic error codes if possible. + if (ev == 0) + return error_condition(0, generic_category()); + if (auto maybe_errc = __win_err_to_errc(ev)) + return error_condition(static_cast<int>(*maybe_errc), generic_category()); + return error_condition(ev, system_category()); +#else +# ifdef _LIBCPP_ELAST if (ev > _LIBCPP_ELAST) return error_condition(ev, system_category()); -#endif // _LIBCPP_ELAST +# endif // _LIBCPP_ELAST return error_condition(ev, generic_category()); +#endif } const error_category& system_category() noexcept { @@ -213,7 +362,7 @@ system_error::~system_error() noexcept {} void __throw_system_error(int ev, const char* what_arg) { #if _LIBCPP_HAS_EXCEPTIONS - std::__throw_system_error(error_code(ev, system_category()), what_arg); + std::__throw_system_error(error_code(ev, generic_category()), what_arg); #else // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily. _LIBCPP_VERBOSE_ABORT( |