public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/redhat/heads/gcc-8-branch)] libstdc++: Fix FS-dependent filesystem tests
@ 2020-09-17 17:14 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2020-09-17 17:14 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:b36e5568251a623687fffde0cdc334572a68d7cd

commit b36e5568251a623687fffde0cdc334572a68d7cd
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Mar 12 17:39:04 2020 +0000

    libstdc++: Fix FS-dependent filesystem tests
    
    These tests were failing on XFS because it doesn't support setting file
    timestamps past 2038, so the expected overflow when reading back a huge
    timestamp into a file_time_type didn't happen.
    
    Additionally, the std::filesystem::file_time_type::clock has an
    epoch that is out of range of 32-bit time_t so testing times around that
    epoch may also fail.
    
    This fixes the tests to give up gracefully if the filesystem doesn't
    support times that can't be represented in 32-bit time_t.
    
    Backport from mainline
    2020-02-28  Jonathan Wakely  <jwakely@redhat.com>
    
            * testsuite/27_io/filesystem/operations/last_write_time.cc: Fixes for
            filesystems that silently truncate timestamps.
            * testsuite/experimental/filesystem/operations/last_write_time.cc:
            Likewise.
    
    (cherry picked from commit 2fa3247fef79ede9ec3638605ea137b0e4d76075)

Diff:
---
 .../27_io/filesystem/operations/last_write_time.cc | 77 ++++++++++++++++------
 .../filesystem/operations/last_write_time.cc       | 58 +++++++++++-----
 2 files changed, 99 insertions(+), 36 deletions(-)

diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
index c815e01a5c6..cedddd1606f 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
@@ -32,9 +32,12 @@
 #if _GLIBCXX_HAVE_UTIME_H
 # include <utime.h>
 #endif
+#include <stdio.h>
 
 using time_type = std::filesystem::file_time_type;
 
+namespace chrono = std::chrono;
+
 void
 test01()
 {
@@ -67,10 +70,15 @@ test01()
 
   auto end_of_time = time_type::duration::max();
   auto last_second
-    = std::chrono::duration_cast<std::chrono::seconds>(end_of_time).count();
+    = chrono::duration_cast<chrono::seconds>(end_of_time).count();
   if (last_second > std::numeric_limits<std::time_t>::max())
-    return; // can't test overflow
+  {
+    puts("Range of time_t is smaller than range of chrono::file_clock, "
+	 "can't test for overflow on this target.");
+    return;
+  }
 
+  // Set mtime to a date past the maximum possible file_time_type:
 #if _GLIBCXX_USE_UTIMENSAT
   struct ::timespec ts[2];
   ts[0].tv_sec = 0;
@@ -84,25 +92,34 @@ test01()
   times.actime = std::numeric_limits<std::time_t>::max() - 1;
   VERIFY( !::utime(p.c_str(), &times) );
 #else
+  puts("No utimensat or utime, giving up.");
   return;
 #endif
 
+  // Try to read back the impossibly-large mtime:
   mtime = last_write_time(p, ec);
-  VERIFY( ec );
-  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
-  VERIFY( mtime == time_type::min() );
+  // Some filesystems (e.g. XFS) silently truncate distant times to
+  // the time_t epochalypse, Jan 19 2038, so we won't get an error when
+  // reading it back:
+  if (ec)
+  {
+    VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+    VERIFY( mtime == time_type::min() );
+  }
+  else
+    puts("No overflow error, filesystem may not support 64-bit time_t.");
 
 #if __cpp_exceptions
-  caught = false;
+  // Once more, with exceptions:
   try {
-    mtime = last_write_time(p);
-  } catch (std::system_error const& e) {
-    caught = true;
-    ec = e.code();
+    auto mtime2 = last_write_time(p);
+    // If it didn't throw, expect to have read back the same value:
+    VERIFY( mtime2 == mtime );
+  } catch (std::filesystem::filesystem_error const& e) {
+    // If it did throw, expect the error_code to be the same:
+    VERIFY( e.code() == ec );
+    VERIFY( e.path1() == p );
   }
-  VERIFY( caught );
-  VERIFY( ec );
-  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
 #endif
 }
 
@@ -111,7 +128,7 @@ bool approx_equal(time_type file_time, time_type expected)
   auto delta = expected - file_time;
   if (delta < delta.zero())
     delta = -delta;
-  return delta < std::chrono::seconds(1);
+  return delta < chrono::seconds(1);
 }
 
 void
@@ -124,20 +141,20 @@ test02()
   std::error_code ec;
   time_type time;
 
-  time = last_write_time(f.path);
   ec = bad_ec;
+  time = last_write_time(f.path);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
   ec = bad_ec;
-  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  time -= chrono::milliseconds(1000 * 60 * 10 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
   ec = bad_ec;
-  time += std::chrono::milliseconds(1000 * 60 * 20 + 15);
+  time += chrono::milliseconds(1000 * 60 * 20 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
@@ -146,6 +163,28 @@ test02()
       < std::numeric_limits<std::int64_t>::max())
     return; // file clock's epoch is out of range for 32-bit time_t
 
+  using sys_time_32b
+    = chrono::time_point<chrono::system_clock, chrono::duration<std::int32_t>>;
+  auto duration_until_2038 = sys_time_32b::max() - sys_time_32b::clock::now();
+  auto file_time_2038 = time_type::clock::now() + duration_until_2038;
+
+  ec = bad_ec;
+  time = file_time_2038 - chrono::seconds(1);
+  // Assume all filesystems can store times that fit in 32-bit time_t
+  // (i.e. up to Jan 19 2038)
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  // Check whether the filesystem supports times larger than 32-bit time_t:
+  time += chrono::seconds(60);
+  last_write_time(f.path, time, ec);
+  if (ec || !approx_equal(last_write_time(f.path), time))
+  {
+    puts("Filesystem seems to truncate times past Jan 19 2038, giving up.");
+    return; // Tests below will fail on this filesystem
+  }
+
   ec = bad_ec;
   // The file clock's epoch:
   time = time_type();
@@ -155,14 +194,14 @@ test02()
 
   ec = bad_ec;
   // A time after the epoch
-  time += std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  time += chrono::milliseconds(1000 * 60 * 10 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
   ec = bad_ec;
   // A time before than the epoch
-  time -= std::chrono::milliseconds(1000 * 60 * 20 + 15);
+  time -= chrono::milliseconds(1000 * 60 * 20 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
index 9d1752fd4fc..e43f755d4d0 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
@@ -22,6 +22,7 @@
 // 15.25 Permissions [fs.op.last_write_time]
 
 #include <experimental/filesystem>
+#include <limits>
 #include <testsuite_fs.h>
 #include <testsuite_hooks.h>
 
@@ -31,9 +32,12 @@
 #if _GLIBCXX_HAVE_UTIME_H
 # include <utime.h>
 #endif
+#include <stdio.h>
 
 using time_type = std::experimental::filesystem::file_time_type;
 
+namespace chrono = std::chrono;
+
 void
 test01()
 {
@@ -66,10 +70,15 @@ test01()
 
   auto end_of_time = time_type::duration::max();
   auto last_second
-    = std::chrono::duration_cast<std::chrono::seconds>(end_of_time).count();
+    = chrono::duration_cast<chrono::seconds>(end_of_time).count();
   if (last_second > std::numeric_limits<std::time_t>::max())
-    return; // can't test overflow
+  {
+    puts("Range of time_t is smaller than range of chrono::file_clock, "
+	 "can't test for overflow on this target.");
+    return;
+  }
 
+  // Set mtime to a date past the maximum possible file_time_type:
 #if _GLIBCXX_USE_UTIMENSAT
   struct ::timespec ts[2];
   ts[0].tv_sec = 0;
@@ -83,25 +92,34 @@ test01()
   times.actime = std::numeric_limits<std::time_t>::max() - 1;
   VERIFY( !::utime(p.c_str(), &times) );
 #else
+  puts("No utimensat or utime, giving up.");
   return;
 #endif
 
+  // Try to read back the impossibly-large mtime:
   mtime = last_write_time(p, ec);
-  VERIFY( ec );
-  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
-  VERIFY( mtime == time_type::min() );
+  // Some filesystems (e.g. XFS) silently truncate distant times to
+  // the time_t epochalypse, Jan 19 2038, so we won't get an error when
+  // reading it back:
+  if (ec)
+  {
+    VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+    VERIFY( mtime == time_type::min() );
+  }
+  else
+    puts("No overflow error, filesystem may not support 64-bit time_t.");
 
 #if __cpp_exceptions
-  caught = false;
+  // Once more, with exceptions:
   try {
-    mtime = last_write_time(p);
-  } catch (std::system_error const& e) {
-    caught = true;
-    ec = e.code();
+    auto mtime2 = last_write_time(p);
+    // If it didn't throw, expect to have read back the same value:
+    VERIFY( mtime2 == mtime );
+  } catch (std::experimental::filesystem::filesystem_error const& e) {
+    // If it did throw, expect the error_code to be the same:
+    VERIFY( e.code() == ec );
+    VERIFY( e.path1() == p );
   }
-  VERIFY( caught );
-  VERIFY( ec );
-  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
 #endif
 }
 
@@ -110,7 +128,7 @@ bool approx_equal(time_type file_time, time_type expected)
   auto delta = expected - file_time;
   if (delta < delta.zero())
     delta = -delta;
-  return delta < std::chrono::seconds(1);
+  return delta < chrono::seconds(1);
 }
 
 void
@@ -118,31 +136,37 @@ test02()
 {
   // write times
 
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
   __gnu_test::scoped_file f;
   std::error_code ec;
   time_type time;
 
+  ec = bad_ec;
   time = last_write_time(f.path);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
-  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  ec = bad_ec;
+  time -= chrono::milliseconds(1000 * 60 * 10 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
-  time += std::chrono::milliseconds(1000 * 60 * 20 + 15);
+  ec = bad_ec;
+  time += chrono::milliseconds(1000 * 60 * 20 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
+  ec = bad_ec;
   time = time_type();
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );
 
-  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  ec = bad_ec;
+  time -= chrono::milliseconds(1000 * 60 * 10 + 15);
   last_write_time(f.path, time, ec);
   VERIFY( !ec );
   VERIFY( approx_equal(last_write_time(f.path), time) );


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-09-17 17:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-17 17:14 [gcc(refs/vendors/redhat/heads/gcc-8-branch)] libstdc++: Fix FS-dependent filesystem tests Jakub Jelinek

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).