Skip to content

<chrono>: integer overflow in weekday::weekday(sys_days::max()) #5153

@cassioneri

Description

@cassioneri

Brief description

The following code fails to compile due to an int addition overflow:

#include <chrono>

using namespace std::chrono;

constexpr auto wd = weekday(sys_days::max());

https://godbolt.org/z/K6dW7bvYq

Details

The overflow occurs in the evaluation of _Tp + 4 below

        _NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept {
            return static_cast<unsigned int>(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6);
        }

Indeed, this addition overflows whenever _Tp > INT_MAX - 4.

Fixes

Provided that the range of long long int is larger than that of int, the obvious fix is declaring _Tp as long long int and an alternative is this:

        _NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept {
            auto const m = unsigned(_Tp) + (_Tp >= 0 ? 4 : 0);
            auto const w = m % 7;
            __assume(w != 7); // not necessary but improves codegen
            return w;
        }

This alternative is better than the obvious fix and better than the current implementation. Indeed, with this fix the codegen of weekday::weekday(const sys_days&) becomes branch-free and avoids div instructions on x64, x86 and arm64.

Test

The alternative above works as an exhaustive test shows:

int main() {

  unsigned int encoding = weekday(sys_days::min()).c_encoding();
  for (auto s = sys_days::min(); s < sys_days::max(); s += days(1)) {
    assert(weekday_ctr(s).c_encoding() == encoding);
    ++encoding;
    if (encoding == 7)
      encoding = 0;
  }
  // One more to go:
  assert(weekday_ctr(sys_days::max()).c_encoding() == encoding);
  std::puts("Success.");
}

(where weekday_ctr is an impersonation of weekday::weekday(const sys_days&) using the fixed _Weekday_from_days.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingchronoC++20 chronofixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions