From ffbad9b76279e23c70bd2df8ba5f3259180e192a Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Wed, 27 Mar 2024 22:54:15 -0700 Subject: [PATCH] progress-bar.cc: fix signed overflow this was caused by the use of std::chrono::duration::max() which gets multiplied by some ratio to calculate nanoseconds to wait. then, it explodes because that is a signed integer overflow. this was definitely a bug. error below: /nix/store/fdiknsmnnczx6brsbppyljcs9hqckawk-gcc-12.3.0/include/c++/12.3.0/bits/chrono.h:225:38: runtime error: signed integer overflow: 9223372036854775807 * 1000000 cannot be represented in type 'long' #0 0x736d376b2b69 in std::chrono::duration> std::chrono::__duration_cast_impl>, std::ratio<1000000l, 1l>, long, false, true>::__cast>( std::chrono::duration> const&) /nix/store/fdiknsmnnczx6brsbppyljcs9hqckawk-gcc-12.3.0/include/c++/12 .3.0/bits/chrono.h:225:38 #1 0x736d376b2b69 in std::enable_if<__is_duration>>::value, std::chr ono::duration>>::type std::chrono::duration_cast>, long, std::ratio<1l, 1000l>>(std::chrono::duration> const&) /nix/store/fdiknsmnnczx6brs bppyljcs9hqckawk-gcc-12.3.0/include/c++/12.3.0/bits/chrono.h:270:9 #2 0x736d376b2b69 in std::enable_if<__is_duration>>::value, std::chr ono::duration>>::type std::chrono::ceil>, long, std::ratio<1l, 1000l>>(std::chrono::duration> const&) /nix/store/fdiknsmnnczx6brsbppyljcs9 hqckawk-gcc-12.3.0/include/c++/12.3.0/bits/chrono.h:386:14 #3 0x736d376b2b69 in std::cv_status std::condition_variable::wait_for>(std::unique_lock&, std::chrono::duration> const&) /nix/store/fdiknsmnnczx6brsbppyljcs9hqckawk-gcc-12.3.0/include/ c++/12.3.0/condition_variable:164:6 #4 0x736d376b1ee9 in std::cv_status nix::Sync::Lock::wait_for>(std::condition_variable&, std::chrono::duration> const&) /home/jade/lix/lix/src/libutil/sync.hh: 65:23 #5 0x736d376b1ee9 in nix::ProgressBar::ProgressBar(bool)::'lambda'()::operator()() const /home/jade/lix/lix/src/libmain/prog ress-bar.cc:99:27 #6 0x736d36de25c2 in execute_native_thread_routine (/nix/store/a3zlvnswi1p8cg7i9w4lpnvaankc7dxx-gcc-12.3.0-lib/lib/libstdc++ .so.6+0xe05c2) #7 0x736d36b6b0e3 in start_thread (/nix/store/1zy01hjzwvvia6h9dq5xar88v77fgh9x-glibc-2.38-44/lib/libc.so.6+0x8b0e3) (BuildId : 287831bffdbdde0ec25dbd021d12bdfc0ab9f5ff) #8 0x736d36bed5e3 in __clone (/nix/store/1zy01hjzwvvia6h9dq5xar88v77fgh9x-glibc-2.38-44/lib/libc.so.6+0x10d5e3) (BuildId: 28 7831bffdbdde0ec25dbd021d12bdfc0ab9f5ff) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /nix/store/fdiknsmnnczx6brsbppyljcs9hqckawk-gcc-12.3.0/include/c++/12.3. 0/bits/chrono.h:225:38 in Change-Id: Ia0303242cdfd5d49385ae9e99718d709625a4633 --- src/libmain/progress-bar.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc index 5c648ccf7..1a68daca2 100644 --- a/src/libmain/progress-bar.cc +++ b/src/libmain/progress-bar.cc @@ -12,6 +12,8 @@ namespace nix { +using namespace std::literals::chrono_literals; + static std::string_view getS(const std::vector & fields, size_t n) { assert(n < fields.size()); @@ -33,6 +35,9 @@ static std::string_view storePathToName(std::string_view path) return i == std::string::npos ? base.substr(0, 0) : base.substr(i + 1); } +// 100 years ought to be enough for anyone (yet sufficiently smaller than max() to not cause signed integer overflow). +constexpr const auto A_LONG_TIME = std::chrono::duration_cast(100 * 365 * 86400s); + class ProgressBar : public Logger { private: @@ -93,7 +98,7 @@ public: state_.lock()->active = isTTY; updateThread = std::thread([&]() { auto state(state_.lock()); - auto nextWakeup = std::chrono::milliseconds::max(); + auto nextWakeup = A_LONG_TIME; while (state->active) { if (!state->haveUpdate) state.wait_for(updateCV, nextWakeup); @@ -350,7 +355,7 @@ public: std::chrono::milliseconds draw(State & state) { - auto nextWakeup = std::chrono::milliseconds::max(); + auto nextWakeup = A_LONG_TIME; state.haveUpdate = false; if (state.paused || !state.active) return nextWakeup;