From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 46E363858D35; Fri, 7 Aug 2020 11:43:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 46E363858D35 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1596800597; bh=0GNcSMy3CQrFlxtAD2spO1X9MVJwMxzgKYw7/Q6syIY=; h=From:To:Subject:Date:From; b=SnD8LkUwZ9GxVAwMX7VpP0WuE06fC6c6VLcStG7F3N0DoD0hchX3ID1ndYhaYj83s jJpN+zGiAwwiDzvHSmMNkMETPI0SxdxjFTXKgzVU713mTMrTR9ft1r1UyMMBKY8fe4 ByivIk/zEMbkznvuVOVAIjXxv20cjaHiMwf51X30= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r8-10395] libstdc++: Fix FS-dependent filesystem tests X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/releases/gcc-8 X-Git-Oldrev: 3b05a417774d40cf1b9fca61630209de8338ba47 X-Git-Newrev: b623cf82022d8837c228c1c9ca6a585318c24e40 Message-Id: <20200807114317.46E363858D35@sourceware.org> Date: Fri, 7 Aug 2020 11:43:17 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Aug 2020 11:43:17 -0000 https://gcc.gnu.org/g:b623cf82022d8837c228c1c9ca6a585318c24e40 commit r8-10395-gb623cf82022d8837c228c1c9ca6a585318c24e40 Author: Jonathan Wakely 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 * 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 #endif +#include 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(end_of_time).count(); + = chrono::duration_cast(end_of_time).count(); if (last_second > std::numeric_limits::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::max() - 1; VERIFY( !::utime(p.c_str(), ×) ); #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::max()) return; // file clock's epoch is out of range for 32-bit time_t + using sys_time_32b + = chrono::time_point>; + 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 +#include #include #include @@ -31,9 +32,12 @@ #if _GLIBCXX_HAVE_UTIME_H # include #endif +#include 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(end_of_time).count(); + = chrono::duration_cast(end_of_time).count(); if (last_second > std::numeric_limits::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::max() - 1; VERIFY( !::utime(p.c_str(), ×) ); #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) );