libstdc++: Use non-throwing increment in recursive_directory_iterator [PR 97731]

As described in the PR, the recursive_directory_iterator constructor
calls advance(ec), but ec is a pointer so it calls _Dir::advance(bool).
The intention was to either call advance() or advance(*ec) depending
whether the pointer is null or not.

This fixes the bug and renames the parameter to ecptr to make similar
mistakes less likely in future.

libstdc++-v3/ChangeLog:

	PR libstdc++/97731
	* src/filesystem/dir.cc (recursive_directory_iterator): Call the
	right overload of _Dir::advance.
	* testsuite/experimental/filesystem/iterators/97731.cc: New test.
This commit is contained in:
Jonathan Wakely 2020-11-05 17:26:13 +00:00
parent 710508c7b1
commit 2f93a2a03a
2 changed files with 60 additions and 7 deletions

View File

@ -187,16 +187,16 @@ struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
fs::recursive_directory_iterator::
recursive_directory_iterator(const path& p, directory_options options,
error_code* ec)
error_code* ecptr)
: _M_options(options), _M_pending(true)
{
if (ec)
ec->clear();
if (posix::DIR* dirp = posix::opendir(p.c_str()))
{
if (ecptr)
ecptr->clear();
auto sp = std::make_shared<_Dir_stack>();
sp->push(_Dir{ dirp, p });
if (sp->top().advance(ec))
if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance())
_M_dirs.swap(sp);
}
else
@ -204,14 +204,18 @@ recursive_directory_iterator(const path& p, directory_options options,
const int err = errno;
if (err == EACCES
&& is_set(options, fs::directory_options::skip_permission_denied))
return;
{
if (ecptr)
ecptr->clear();
return;
}
if (!ec)
if (!ecptr)
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
"recursive directory iterator cannot open directory", p,
std::error_code(err, std::generic_category())));
ec->assign(err, std::generic_category());
ecptr->assign(err, std::generic_category());
}
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2020 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 <testsuite_hooks.h>
bool used_custom_readdir = false;
extern "C" void* readdir(void*)
{
used_custom_readdir = true;
errno = EIO;
return nullptr;
}
void
test01()
{
using std::experimental::filesystem::recursive_directory_iterator;
std::error_code ec;
recursive_directory_iterator it(".", ec);
if (used_custom_readdir)
VERIFY( ec.value() == EIO );
}
int
main()
{
test01();
}