diff options
| author | Andrey Khalyavin <[email protected]> | 2022-06-02 00:33:58 +0300 | 
|---|---|---|
| committer | Andrey Khalyavin <[email protected]> | 2022-06-02 00:33:58 +0300 | 
| commit | e673b301b03ea16c0bdc9537de9501f1c9b4cf28 (patch) | |
| tree | 27631393b7e7889db9ac6fcbd8e6b61b0f5a1ba0 /contrib/libs/cxxsupp/libcxx/src | |
| parent | 5424a48cca3b5a79e8431052b74fafb9768e669e (diff) | |
Update libc++ to eaadc451 (4 Feb 2022).
Notable changes:
* fix chrono::duration constructor constraint
* delete base class for std::basic_string
* add ranges::in_out_out_result and ranges::in_in_out_result
* implement indirectly_copyable{,_storable} concepts
* rename __referenceable to __can_reference to match text of the standard
* add _LIBCPP_HAS_NO_CONCEPTS guards where concepts are used
* simplify no concepts guards
* add specifications for basic_common_reference and common_type for pair
* make _VSTD an alias for std so that it can be removed in the future
* remove std from friend declaration to facilitate switch from _VSTD to std
* fix TOCTOU issue with std::filesystem::remove_all
* add additional constraints to std::ranges::get for subranges when N == 0
* pick unique bit for __regex_word constant
* use vsnprintf instead of _vsnprintf on Windows
* ADL-proof ranges::iter_swap and ranges::iter_move
* implement std::ranges::distance
* merge _LIBCPP_HAS_NO_RANGES into _LIBCPP_HAS_NO_CONCEPTS
ref:b637aa39f39243eeac99a2109af1daaac7c29316
Diffstat (limited to 'contrib/libs/cxxsupp/libcxx/src')
| -rw-r--r-- | contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp | 107 | ||||
| -rw-r--r-- | contrib/libs/cxxsupp/libcxx/src/string.cpp | 21 | ||||
| -rw-r--r-- | contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp | 4 | 
3 files changed, 124 insertions, 8 deletions
diff --git a/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp b/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp index d69fff11a03..8e1a8ef1ab4 100644 --- a/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp @@ -24,9 +24,10 @@  # define NOMINMAX  # include <windows.h>  #else -# include <unistd.h> +# include <dirent.h>  # include <sys/stat.h>  # include <sys/statvfs.h> +# include <unistd.h>  #endif  #include <time.h>  #include <fcntl.h> /* values for fchmodat */ @@ -1342,6 +1343,19 @@ bool __remove(const path& p, error_code* ec) {    return true;  } +// We currently have two implementations of `__remove_all`. The first one is general and +// used on platforms where we don't have access to the `openat()` family of POSIX functions. +// That implementation uses `directory_iterator`, however it is vulnerable to some race +// conditions, see https://reviews.llvm.org/D118134 for details. +// +// The second implementation is used on platforms where `openat()` & friends are available, +// and it threads file descriptors through recursive calls to avoid such race conditions. +#if defined(_LIBCPP_WIN32API) +# define REMOVE_ALL_USE_DIRECTORY_ITERATOR +#endif + +#if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR) +  namespace {  uintmax_t remove_all_impl(path const& p, error_code& ec) { @@ -1381,6 +1395,97 @@ uintmax_t __remove_all(const path& p, error_code* ec) {    return count;  } +#else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR + +namespace { + +template <class Cleanup> +struct scope_exit { +  explicit scope_exit(Cleanup const& cleanup) +    : cleanup_(cleanup) +  { } + +  ~scope_exit() { cleanup_(); } + +private: +  Cleanup cleanup_; +}; + +uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) { +  // First, try to open the path as a directory. +  const int options = O_CLOEXEC | O_RDONLY | O_DIRECTORY | O_NOFOLLOW; +  int fd = ::openat(parent_directory, p.c_str(), options); +  if (fd != -1) { +    // If that worked, iterate over the contents of the directory and +    // remove everything in it, recursively. +    scope_exit close_fd([=] { ::close(fd); }); +    DIR* stream = ::fdopendir(fd); +    if (stream == nullptr) { +      ec = detail::capture_errno(); +      return 0; +    } +    scope_exit close_stream([=] { ::closedir(stream); }); + +    uintmax_t count = 0; +    while (true) { +      auto [str, type] = detail::posix_readdir(stream, ec); +      static_assert(std::is_same_v<decltype(str), std::string_view>); +      if (str == "." || str == "..") { +        continue; +      } else if (ec || str.empty()) { +        break; // we're done iterating through the directory +      } else { +        count += remove_all_impl(fd, str, ec); +      } +    } + +    // Then, remove the now-empty directory itself. +    if (::unlinkat(parent_directory, p.c_str(), AT_REMOVEDIR) == -1) { +      ec = detail::capture_errno(); +      return count; +    } + +    return count + 1; // the contents of the directory + the directory itself +  } + +  ec = detail::capture_errno(); + +  // If we failed to open `p` because it didn't exist, it's not an +  // error -- it might have moved or have been deleted already. +  if (ec == errc::no_such_file_or_directory) { +    ec.clear(); +    return 0; +  } + +  // If opening `p` failed because it wasn't a directory, remove it as +  // a normal file instead. Note that `openat()` can return either ENOTDIR +  // or ELOOP depending on the exact reason of the failure. +  if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels) { +    ec.clear(); +    if (::unlinkat(parent_directory, p.c_str(), /* flags = */0) == -1) { +      ec = detail::capture_errno(); +      return 0; +    } +    return 1; +  } + +  // Otherwise, it's a real error -- we don't remove anything. +  return 0; +} + +} // end namespace + +uintmax_t __remove_all(const path& p, error_code* ec) { +  ErrorHandler<uintmax_t> err("remove_all", ec, &p); +  error_code mec; +  uintmax_t count = remove_all_impl(AT_FDCWD, p, mec); +  if (mec) +    return err.report(mec); +  return count; +} + +#endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR +  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) diff --git a/contrib/libs/cxxsupp/libcxx/src/string.cpp b/contrib/libs/cxxsupp/libcxx/src/string.cpp index 3c63f408240..3cde2e9005b 100644 --- a/contrib/libs/cxxsupp/libcxx/src/string.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/string.cpp @@ -21,15 +21,26 @@  _LIBCPP_BEGIN_NAMESPACE_STD -#ifndef _LIBCPP_ABI_NO_BASIC_STRING_BASE_CLASS +#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON + +template <bool> +struct __basic_string_common; + +// The struct isn't declared anymore in the headers. It's only here for ABI compatibility. +template <> +struct __basic_string_common<true> { +    _LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_length_error() const; +    _LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_out_of_range() const; +}; +  void __basic_string_common<true>::__throw_length_error() const { -    _VSTD::__throw_length_error("basic_string"); +    std::__throw_length_error("basic_string");  } -  void __basic_string_common<true>::__throw_out_of_range() const { -    _VSTD::__throw_out_of_range("basic_string"); +    std::__throw_out_of_range("basic_string");  } -#endif + +#endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON  #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;  #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp index 11702a788b1..115d975bbf9 100644 --- a/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/support.cpp @@ -23,7 +23,7 @@ int __libcpp_vasprintf( char **sptr, const char *__restrict format, va_list ap )      // Query the count required.      va_list ap_copy;      va_copy(ap_copy, ap); -    int count = _vsnprintf( NULL, 0, format, ap_copy ); +    int count = vsnprintf( NULL, 0, format, ap_copy );      va_end(ap_copy);      if (count < 0)          return count; @@ -33,7 +33,7 @@ int __libcpp_vasprintf( char **sptr, const char *__restrict format, va_list ap )          return -1;      // If we haven't used exactly what was required, something is wrong.      // Maybe bug in vsnprintf. Report the error and return. -    if (_vsnprintf(p, buffer_size, format, ap) != count) { +    if (vsnprintf(p, buffer_size, format, ap) != count) {          free(p);          return -1;      }  | 
