summaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2020-02-27 16:38:00 +0000
committerJonathan Wakely <jwakely@redhat.com>2020-02-28 12:58:28 +0000
commita51a546c1704cd572c35c11e539568c04d99e7d1 (patch)
tree1ebf8ff9f963c803e435c0b6edeee4f51150906f /libstdc++-v3
parent86e2dc22c91a722d2624c0010d81f1ce4b911bbd (diff)
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. * 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.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog5
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc77
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc58
3 files changed, 104 insertions, 36 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 24ce2a140db..9fe2fd2caa8 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,10 @@
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.
+
* testsuite/21_strings/basic_string/cons/char/1.cc: Disable
-Wstringop-overflow warnings.
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 a6be926143c..2bba02f6899 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.string().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 4e3ea6754f9..13313a9a640 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.string().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) );