]> git.ipfire.org Git - thirdparty/gcc.git/commit
libstdc++: Avoid overflow in timeout conversions [PR113327]
authorJonathan Wakely <jwakely@redhat.com>
Thu, 9 Oct 2025 10:09:34 +0000 (11:09 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 14 Oct 2025 16:26:42 +0000 (17:26 +0100)
commit5dba17a3e709859968f939354e6e5e8d796012d3
tree4d6f523ebc8d2747099264db3a393f496ae5f8f1
parentec331001eaa1e42c6ff9536fa51aeaf2a1c86a6a
libstdc++: Avoid overflow in timeout conversions [PR113327]

When converting from a coarse duration with a very large value, the
existing code scales that up to chrono::seconds which overflows the
chrono::seconds::rep type. For example, sleep_for(chrono::hours::max())
tries to calculate LLONG_MAX * 3600, which overflows to -3600 and so the
sleep returns immediately.

The solution in this commit is inspired by this_thread::sleep_for in
libc++ which compares the duration argument to
chrono::duration<long double>(nanoseconds::max()) and limits the
duration to nanoseconds::max(). Because we split the duration into
seconds and nanoseconds, we can use seconds::max() as our upper limit.

We might need to limit further if seconds::max() doesn't fit in the
type used for sleeping, which is one of std::time_t, unsigned int, or
chrono::milliseconds.

To fix this everywhere that uses timeouts, new functions are introduced
for converting from a chrono::duration or chrono::time_point to a
timespec (or __gthread_time_t which is just a timespec on Linux). These
functions provide one central place where we can avoid overflow and also
handle negative timeouts (as these produce errors when passed to OS
functions that do not accept absolute times before the epoch). All
negative durations are converted to zero, and negative time_points are
converted to the epoch.

The new __to_timeout_gthread_time_t function in <bits/std_mutex.h>
requires adding <bits/chrono.h> to that header, but that only affects
<syncstream>. All other consumers of <bits/std_mutex.h> were already
including <bits/chrono.h> for timeouts (e.g. <shared_mutex> and
<condition_variable>).

libstdc++-v3/ChangeLog:

PR libstdc++/113327
PR libstdc++/116586
PR libstdc++/119258
PR libstdc++/58931
* include/bits/chrono.h (__to_timeout_timespec): New overloaded
function templates for converting chrono types to timespec.
* include/bits/std_mutex.h (__to_timeout_gthread_time_t): New
function template for converting time_point to __gthread_time_t.
* include/bits/this_thread_sleep.h (sleep_for): Use
__to_timeout_timespec.
(__sleep_for): Remove namespace-scope declaration.
* include/std/condition_variable: Likewise.
* include/std/mutex: Likewise.
* include/std/shared_mutex: Likewise.
* src/c++11/thread.cc (limit): New helper function.
(__sleep_for): Use limit to prevent overflow when converting
chrono::seconds to time_t, unsigned, or chrono::milliseconds.
* src/c++20/atomic.cc: Use __to_timeout_timespec and
__to_timeout_gthread_time_t for timeouts.
* testsuite/30_threads/this_thread/113327.cc: New test.

Reviewed-by: Mike Crowe <mac@mcrowe.com>
Reviewed-by: Tomasz KamiƄski <tkaminsk@redhat.com>
libstdc++-v3/include/bits/chrono.h
libstdc++-v3/include/bits/std_mutex.h
libstdc++-v3/include/bits/this_thread_sleep.h
libstdc++-v3/include/std/condition_variable
libstdc++-v3/include/std/mutex
libstdc++-v3/include/std/shared_mutex
libstdc++-v3/src/c++11/thread.cc
libstdc++-v3/src/c++20/atomic.cc
libstdc++-v3/testsuite/30_threads/this_thread/113327.cc [new file with mode: 0644]