public inbox for libstdc++-cvs@sourceware.org help / color / mirror / Atom feed
From: Jonathan Wakely <redi@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r10-10839] libstdc++: Reset filesystem::recursive_directory_iterator on error Date: Wed, 15 Jun 2022 08:14:49 +0000 (GMT) [thread overview] Message-ID: <20220615081449.D2EFB3856DDE@sourceware.org> (raw) https://gcc.gnu.org/g:92d5f0c71ea913b9b36c47ab392cc1225434ce3c commit r10-10839-g92d5f0c71ea913b9b36c47ab392cc1225434ce3c Author: Jonathan Wakely <jwakely@redhat.com> Date: Mon Jan 31 21:12:53 2022 +0000 libstdc++: Reset filesystem::recursive_directory_iterator on error The standard requires directory iterators to become equal to the end iterator value if they report an error. Some members functions of filesystem::recursive_directory_iterator fail to do that. libstdc++-v3/ChangeLog: * src/c++17/fs_dir.cc (recursive_directory_iterator::increment): Reset state to past-the-end iterator on error. (fs::recursive_directory_iterator::pop(error_code&)): Likewise. (fs::recursive_directory_iterator::pop()): Check _M_dirs before it might get reset. * src/filesystem/dir.cc (recursive_directory_iterator): Likewise, for the TS implementation. * testsuite/27_io/filesystem/iterators/error_reporting.cc: New test. * testsuite/experimental/filesystem/iterators/error_reporting.cc: New test. (cherry picked from commit ec09a5335f0ade7071f6157dfd97dbb3de3e4f97) Diff: --- libstdc++-v3/src/c++17/fs_dir.cc | 12 +- libstdc++-v3/src/filesystem/dir.cc | 12 +- .../27_io/filesystem/iterators/error_reporting.cc | 135 ++++++++++++++++++++ .../filesystem/iterators/error_reporting.cc | 136 +++++++++++++++++++++ 4 files changed, 291 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/src/c++17/fs_dir.cc b/libstdc++-v3/src/c++17/fs_dir.cc index 21a80b7d56b..d728ac70e8a 100644 --- a/libstdc++-v3/src/c++17/fs_dir.cc +++ b/libstdc++-v3/src/c++17/fs_dir.cc @@ -306,6 +306,10 @@ fs::recursive_directory_iterator::increment(error_code& ec) return *this; } } + + if (ec) + _M_dirs.reset(); + return *this; } @@ -329,16 +333,20 @@ fs::recursive_directory_iterator::pop(error_code& ec) ec.clear(); return; } - } while (!_M_dirs->top().advance(skip_permission_denied, ec)); + } while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec); + + if (ec) + _M_dirs.reset(); } void fs::recursive_directory_iterator::pop() { + [[maybe_unused]] const bool dereferenceable = _M_dirs != nullptr; error_code ec; pop(ec); if (ec) - _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs + _GLIBCXX_THROW_OR_ABORT(filesystem_error(dereferenceable ? "recursive directory iterator cannot pop" : "non-dereferenceable recursive directory iterator cannot pop", ec)); diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc index 64acb68f7d2..300e8c3ec64 100644 --- a/libstdc++-v3/src/filesystem/dir.cc +++ b/libstdc++-v3/src/filesystem/dir.cc @@ -289,6 +289,10 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept return *this; } } + + if (ec) + _M_dirs.reset(); + return *this; } @@ -312,16 +316,20 @@ fs::recursive_directory_iterator::pop(error_code& ec) ec.clear(); return; } - } while (!_M_dirs->top().advance(skip_permission_denied, ec)); + } while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec); + + if (ec) + _M_dirs.reset(); } void fs::recursive_directory_iterator::pop() { + [[maybe_unused]] const bool dereferenceable = _M_dirs != nullptr; error_code ec; pop(ec); if (ec) - _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs + _GLIBCXX_THROW_OR_ABORT(filesystem_error(dereferenceable ? "recursive directory iterator cannot pop" : "non-dereferenceable recursive directory iterator cannot pop", ec)); diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc new file mode 100644 index 00000000000..81ef1069367 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc @@ -0,0 +1,135 @@ +// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do run { target { c++17 } } } +// { dg-require-filesystem-ts "" } + +#include <filesystem> +#include <cerrno> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <testsuite_hooks.h> +#include <testsuite_fs.h> + +int choice; + +struct dirent global_dirent; + +extern "C" struct dirent* readdir(DIR*) +{ + switch (choice) + { + case 1: + global_dirent.d_ino = 999; + global_dirent.d_type = DT_REG; + global_dirent.d_reclen = 0; + std::char_traits<char>::copy(global_dirent.d_name, "file", 5); + choice = 0; + return &global_dirent; + case 2: + global_dirent.d_ino = 111; + global_dirent.d_type = DT_DIR; + global_dirent.d_reclen = 60; + std::char_traits<char>::copy(global_dirent.d_name, "subdir", 7); + choice = 1; + return &global_dirent; + default: + errno = EIO; + return nullptr; + } + return &global_dirent; +} + +void +test01() +{ + namespace fs = std::filesystem; + std::error_code ec; + choice = 1; + fs::recursive_directory_iterator it(".", ec); + if (choice == 0) // custom readdir was called + { + it.increment(ec); + VERIFY( ec.value() == EIO ); + VERIFY( it == end(it) ); + } + else + { + puts("Custom readdir not used, cannot test error handling"); + exit(0); + } + +#if __cpp_exceptions + choice = 1; + fs::recursive_directory_iterator it2(".", ec); + if (choice == 0) + { + try { + ++it2; + VERIFY( false ); + } catch (const fs::filesystem_error& e) { + VERIFY( e.code().value() == EIO ); + VERIFY( it2 == end(it2) ); + } + } +#endif +} + +void +test02() +{ + namespace fs = std::filesystem; + auto dir = __gnu_test::nonexistent_path(); + fs::create_directories(dir/"subdir"); + + std::error_code ec; + choice = 2; + fs::recursive_directory_iterator it(dir, ec); + if (choice == 1) + { + ++it; + it.pop(ec); + VERIFY( ec.value() == EIO ); + VERIFY( it == end(it) ); + } + +#if __cpp_exceptions + choice = 2; + fs::recursive_directory_iterator it2(dir, ec); + if (choice == 1) + { + ++it2; + try { + it2.pop(); + VERIFY( false ); + } catch (const fs::filesystem_error& e) { + VERIFY( e.code().value() == EIO ); + VERIFY( it2 == end(it2) ); + } + } +#endif + + fs::remove_all(dir, ec); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc b/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc new file mode 100644 index 00000000000..ade62732028 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/filesystem/iterators/error_reporting.cc @@ -0,0 +1,136 @@ +// Copyright (C) 2020-2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-DUSE_FILESYSTEM_TS -lstdc++fs" } +// { dg-do run { target { c++11 } } } +// { dg-require-filesystem-ts "" } + +#include <experimental/filesystem> +#include <cerrno> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <testsuite_hooks.h> +#include <testsuite_fs.h> + +int choice; + +struct dirent global_dirent; + +extern "C" struct dirent* readdir(DIR*) +{ + switch (choice) + { + case 1: + global_dirent.d_ino = 999; + global_dirent.d_type = DT_REG; + global_dirent.d_reclen = 0; + std::char_traits<char>::copy(global_dirent.d_name, "file", 5); + choice = 0; + return &global_dirent; + case 2: + global_dirent.d_ino = 111; + global_dirent.d_type = DT_DIR; + global_dirent.d_reclen = 60; + std::char_traits<char>::copy(global_dirent.d_name, "subdir", 7); + choice = 1; + return &global_dirent; + default: + errno = EIO; + return nullptr; + } + return &global_dirent; +} + +void +test01() +{ + namespace fs = std::experimental::filesystem; + std::error_code ec; + choice = 1; + fs::recursive_directory_iterator it(".", ec); + if (choice == 0) // custom readdir was called + { + it.increment(ec); + VERIFY( ec.value() == EIO ); + VERIFY( it == end(it) ); + } + else + { + puts("Custom readdir not used, cannot test error handling"); + exit(0); + } + +#if __cpp_exceptions + choice = 1; + fs::recursive_directory_iterator it2(".", ec); + if (choice == 0) // custom readdir was called + { + try { + ++it2; + VERIFY( false ); + } catch (const fs::filesystem_error& e) { + VERIFY( e.code().value() == EIO ); + VERIFY( it2 == end(it2) ); + } + } +#endif +} + +void +test02() +{ + namespace fs = std::experimental::filesystem; + auto dir = __gnu_test::nonexistent_path(); + fs::create_directories(dir/"subdir"); + + std::error_code ec; + choice = 2; + fs::recursive_directory_iterator it(dir, ec); + if (choice == 1) + { + ++it; + it.pop(ec); + VERIFY( ec.value() == EIO ); + VERIFY( it == end(it) ); + } + +#if __cpp_exceptions + choice = 2; + fs::recursive_directory_iterator it2(dir, ec); + if (choice == 1) + { + ++it2; + try { + it2.pop(); + VERIFY( false ); + } catch (const fs::filesystem_error& e) { + VERIFY( e.code().value() == EIO ); + VERIFY( it2 == end(it2) ); + } + } +#endif + + fs::remove_all(dir, ec); +} + +int +main() +{ + test01(); + test02(); +}
reply other threads:[~2022-06-15 8:14 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220615081449.D2EFB3856DDE@sourceware.org \ --to=redi@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ --cc=libstdc++-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).