mirror of git://gcc.gnu.org/git/gcc.git
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<days::rep>::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.
This commit is contained in:
parent
86a0df1a6c
commit
f6ce081d0f
|
@ -930,8 +930,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:
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// Class template day [time.cal.weekday]
|
||||
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
|
||||
constexpr void
|
||||
constexpr_weekday()
|
||||
|
@ -37,6 +38,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<rep>::max()}}};
|
||||
constexpr weekday min{sys_days{days{numeric_limits<rep>::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);
|
||||
|
|
Loading…
Reference in New Issue