From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 3649F38582B4; Tue, 12 Mar 2024 14:17:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3649F38582B4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1710253051; bh=/ZWLiId5fPDAX0dNdWXR3RlThTpmzz5nAwNb4rb2Nqs=; h=From:To:Subject:Date:From; b=pQ/g13flrORJxOdnP2g7KGVY1hy4fP0bNQP6UTo3c4Rnvkm8Uct2laA9a90ikJKaO 077FdbdJTdXqRcm9Vu57BzbAKmMLavHPFHd9IPcuDqudBQdCljjZT+DzjqePMs8zjH r5PNAcxDqc1ESG9RKghX0g9F6aTPYc4lbL9MY8Dw= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-8424] libstdc++: Fix UB in weekday::weekday(sys_days) and add test X-Act-Checkin: gcc X-Git-Author: Cassio Neri X-Git-Refname: refs/heads/releases/gcc-13 X-Git-Oldrev: 779563cff2e18e7891abf57aeee90e8db5035eb5 X-Git-Newrev: d1472711efc77d5ddc2fa6d5eff57baca584c8ef Message-Id: <20240312141731.3649F38582B4@sourceware.org> Date: Tue, 12 Mar 2024 14:17:31 +0000 (GMT) List-Id: https://gcc.gnu.org/g:d1472711efc77d5ddc2fa6d5eff57baca584c8ef commit r13-8424-gd1472711efc77d5ddc2fa6d5eff57baca584c8ef Author: Cassio Neri Date: Sun Nov 12 01:33:52 2023 +0000 libstdc++: Fix UB in weekday::weekday(sys_days) and add test The following has undefined behaviour (signed overflow) [1]: weekday max{sys_days{days{numeric_limits::max()}}}; The issue is in this line when __n is very large and __n + 4 overflows: return weekday(__n >= -4 ? (__n + 4) % 7 : (__n + 5) % 7 + 6); In addition to fixing this bug, the new implementation makes the compiler emit shorter and branchless code for x86-64 and ARM [2]. [1] https://godbolt.org/z/1s5bv7KfT [2] https://godbolt.org/z/zKsabzrhs libstdc++-v3/ChangeLog: * include/std/chrono (weekday::_S_from_days): Fix UB. * testsuite/std/time/weekday/1.cc: Add test for overflow. (cherry picked from commit f6ce081d0ffb5f25d71eb2f30fcfdff7f20dba22) Diff: --- libstdc++-v3/include/std/chrono | 11 +++++++++-- libstdc++-v3/testsuite/std/time/weekday/1.cc | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index ac7febbaa2c..fb8d6c82e8a 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -936,8 +936,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static constexpr weekday _S_from_days(const days& __d) { - auto __n = __d.count(); - return weekday(__n >= -4 ? (__n + 4) % 7 : (__n + 5) % 7 + 6); + using _Rep = days::rep; + using _URep = make_unsigned_t<_Rep>; + const auto __n = __d.count(); + const auto __m = static_cast<_URep>(__n); + + // 1970-01-01 (__n = 0, __m = 0 ) -> Thursday (4) + // 1969-31-12 (__n = -1, __m = _URep(-1)) -> Wednesday (3) + const auto __offset = __n >= 0 ? _URep(4) : 3 - _URep(-1) % 7 - 7; + return weekday((__m + __offset) % 7); } public: diff --git a/libstdc++-v3/testsuite/std/time/weekday/1.cc b/libstdc++-v3/testsuite/std/time/weekday/1.cc index 1e018eaa3e0..bfc617c4cc8 100644 --- a/libstdc++-v3/testsuite/std/time/weekday/1.cc +++ b/libstdc++-v3/testsuite/std/time/weekday/1.cc @@ -21,6 +21,7 @@ // Class template day [time.cal.weekday] #include +#include constexpr void constexpr_weekday() @@ -38,6 +39,14 @@ constexpr_weekday() static_assert(weekday{3}[2].weekday() == weekday{3}); static_assert(weekday{3}[last].weekday() == weekday{3}); + // Test for UB (overflow). + { + using rep = days::rep; + using std::numeric_limits; + constexpr weekday max{sys_days{days{numeric_limits::max()}}}; + constexpr weekday min{sys_days{days{numeric_limits::min()}}}; + } + static_assert(weekday{sys_days{1900y/January/1}} == Monday); static_assert(weekday{sys_days{1970y/January/1}} == Thursday); static_assert(weekday{sys_days{2020y/August/21}} == Friday);