aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2019-04-05 17:56:14 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2019-04-05 17:56:14 +0100
commitd96f11a2720c8ddfc3d181b181cfaadd888323cd (patch)
treeafbf6b6816e29fd29cd900906f354e82fde3df91
parent10f26de9155b71a2bd5055060004420939cf7a2d (diff)
downloadgcc-d96f11a2720c8ddfc3d181b181cfaadd888323cd.zip
gcc-d96f11a2720c8ddfc3d181b181cfaadd888323cd.tar.gz
gcc-d96f11a2720c8ddfc3d181b181cfaadd888323cd.tar.bz2
Make filesystem::path safe for self assignment
The standard says "If *this and p are the same object, has no effect." Previously we ended up clearing the path. * include/bits/fs_path.h (path::operator=(path&&)): Check for self assignment. * src/c++17/fs_path.cc (path::operator=(const path&)): Likewise. * testsuite/27_io/filesystem/path/assign/copy.cc: Test self assignment. From-SVN: r270171
-rw-r--r--libstdc++-v3/ChangeLog6
-rw-r--r--libstdc++-v3/include/bits/fs_path.h3
-rw-r--r--libstdc++-v3/src/c++17/fs_path.cc3
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc18
4 files changed, 30 insertions, 0 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index a34428f..4275142 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,11 @@
2019-04-05 Jonathan Wakely <jwakely@redhat.com>
+ * include/bits/fs_path.h (path::operator=(path&&)): Check for self
+ assignment.
+ * src/c++17/fs_path.cc (path::operator=(const path&)): Likewise.
+ * testsuite/27_io/filesystem/path/assign/copy.cc: Test self
+ assignment.
+
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 96033f6..bf7c65c 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -877,6 +877,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
inline path&
path::operator=(path&& __p) noexcept
{
+ if (&__p == this) [[__unlikely__]]
+ return *this;
+
_M_pathname = std::move(__p._M_pathname);
_M_cmpts = std::move(__p._M_cmpts);
__p.clear();
diff --git a/libstdc++-v3/src/c++17/fs_path.cc b/libstdc++-v3/src/c++17/fs_path.cc
index 268b562..605f62c 100644
--- a/libstdc++-v3/src/c++17/fs_path.cc
+++ b/libstdc++-v3/src/c++17/fs_path.cc
@@ -444,6 +444,9 @@ path::_List::reserve(int newcap, bool exact = false)
path&
path::operator=(const path& p)
{
+ if (&p == this) [[__unlikely__]]
+ return *this;
+
_M_pathname.reserve(p._M_pathname.length());
_M_cmpts = p._M_cmpts; // might throw
_M_pathname = p._M_pathname; // won't throw because we reserved enough space
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc
index 6c24e3a..775dbff 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc
@@ -20,6 +20,7 @@
#include <filesystem>
#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
using std::filesystem::path;
using __gnu_test::compare_paths;
@@ -47,9 +48,26 @@ test02()
}
}
+void
+test03()
+{
+ // self assignment should have no effect
+ const path orig = "foo/bar/baz";
+ path p = orig;
+ const auto ptr1 = p.c_str();
+ const auto ptr2 = p.begin()->c_str();
+ p = std::move(p);
+ __gnu_test::compare_paths(p, orig);
+ p = p;
+ __gnu_test::compare_paths(p, orig);
+ VERIFY( ptr1 == p.c_str() );
+ VERIFY( ptr2 == p.begin()->c_str() );
+}
+
int
main()
{
test01();
test02();
+ test03();
}