https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93201
Bug ID: 93201
Summary: std::filesystem::remove_all fails to remove large
files
Product: gcc
Version: 9.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: redi at gcc dot gnu.org
Target Milestone: ---
#include <fstream>
#include <filesystem>
int main(int argc, char** argv)
{
if (argc < 2)
return 1;
std::filesystem::path dir(argv[1]);
std::error_code ec;
create_directory(dir, ec); // ignore errors
std::ofstream file{dir/"file"};
std::string s;
s.resize(1 << 20);
for (unsigned i = 1 << 12; i; --i)
file.write(s.data(), s.size());
remove_all(dir);
}
With GCC 9 this fails to remove the directory:
tmp$ ./a.out out
terminate called after throwing an instance of
'std::filesystem::__cxx11::filesystem_error'
what(): filesystem error: cannot remove all: Directory not empty [out]
Aborted (core dumped)
tmp$ ls -l out
total 4194304
-rw-rw-r--. 1 jwakely jwakely 4294967296 Jan 8 12:01 file
The problem is that remove_all("dir/file", ec) calls status("dir/file", ec)
which fails (with the same error as PR 91947 comment 2), but then the call to
d.increment(ec) clears the error_code:
if (s.type() == file_type::directory)
{
for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
count += fs::remove_all(d->path(), ec);
if (ec.value() == ENOENT)
ec.clear();
else if (ec)
return -1;
}
This means that the "if (ec)" test only ever fails if d.increment(ec)
encounters an error.
The testcase works correctly on trunk because std::filesystem is built with
LFS, but the remove_all bug that clears the error_code is still latent on
trunk.