Make filesystem::path safe for self assignment
authorJonathan Wakely <jwakely@redhat.com>
Fri, 5 Apr 2019 16:56:14 +0000 (17:56 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 5 Apr 2019 16:56:14 +0000 (17:56 +0100)
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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/fs_path.h
libstdc++-v3/src/c++17/fs_path.cc
libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc

index a34428f762b8264cb469e5db88b38067ae37b73e..42751424d535a73baa049921713edcab158f7365 100644 (file)
@@ -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.
index 96033f68c36cd86c0b7f39919760b9c17e9ba22a..bf7c65c9cad24bb1e830dc79cc2fb1ef13a4d15e 100644 (file)
@@ -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();
index 268b5621509d9f3696ee3f1ffac3bca6d4924e7a..605f62cbf816aa435712228fa0ac65281ecc1ea4 100644 (file)
@@ -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
index 6c24e3ae7b9425c0876cd077359ccc87a1396687..775dbffad36860374291dbdaf34a334e23a975fd 100644 (file)
@@ -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();
 }