Bug 119258 - All uses of relative timeouts should correctly handle overflow in duration conversions
Summary: All uses of relative timeouts should correctly handle overflow in duration co...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 15.0
: P3 normal
Target Milestone: 16.0
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on: 113327
Blocks:
  Show dependency treegraph
 
Reported: 2025-03-12 22:28 UTC by Jonathan Wakely
Modified: 2025-10-14 20:49 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2025-03-12 22:28:01 UTC
This is the general case of Bug 113327. That one is specific to this_thread::sleep_for but we have the same issue in other places where we convert a relative timeout to chrono::seconds. If the original type has a coarser duration than seconds, the value might overflow chrono::seconds::rep.

This affects timed mutexes, condition variables, futures ...
Comment 1 GCC Commits 2025-10-14 16:34:47 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:5dba17a3e709859968f939354e6e5e8d796012d3

commit r16-4425-g5dba17a3e709859968f939354e6e5e8d796012d3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 9 11:09:34 2025 +0100

    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>
Comment 2 Jonathan Wakely 2025-10-14 20:49:25 UTC
Fixed for GCC 16