Change sleep_for, sleep_until, and the condition_variable timed wait
functions to protect against duration and time_point overflow.  Since
we're about to wait anyway, we can afford to spend a few more cycles on
this checking.  I purposefully did not treat the timed try_locks with
overflow checking.  This fixes
http://llvm.org/bugs/show_bug.cgi?id=13721 .  I'm unsure if the standard
needs clarification in this area, or if this is simply QOI.  The
<chrono> facilities were never intended to overflow check, but just to
not overflow if durations stayed within +/- 292 years.

llvm-svn: 162925
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: aad745a024a3d0fd573ac9649d4c659e6a713702
diff --git a/include/__mutex_base b/include/__mutex_base
index 4fdcb61..1782e7c 100644
--- a/include/__mutex_base
+++ b/include/__mutex_base
@@ -323,11 +323,6 @@
     template <class _Predicate>
         void wait(unique_lock<mutex>& __lk, _Predicate __pred);
 
-    template <class _Duration>
-        cv_status
-        wait_until(unique_lock<mutex>& __lk,
-                   const chrono::time_point<chrono::system_clock, _Duration>& __t);
-
     template <class _Clock, class _Duration>
         cv_status
         wait_until(unique_lock<mutex>& __lk,
@@ -382,28 +377,13 @@
         wait(__lk);
 }
 
-template <class _Duration>
-cv_status
-condition_variable::wait_until(unique_lock<mutex>& __lk,
-                 const chrono::time_point<chrono::system_clock, _Duration>& __t)
-{
-    using namespace chrono;
-    typedef time_point<system_clock, nanoseconds> __nano_sys_tmpt;
-    __do_timed_wait(__lk,
-                  __nano_sys_tmpt(__ceil<nanoseconds>(__t.time_since_epoch())));
-    return system_clock::now() < __t ? cv_status::no_timeout :
-                                       cv_status::timeout;
-}
-
 template <class _Clock, class _Duration>
 cv_status
 condition_variable::wait_until(unique_lock<mutex>& __lk,
                                const chrono::time_point<_Clock, _Duration>& __t)
 {
     using namespace chrono;
-    system_clock::time_point     __s_now = system_clock::now();
-    typename _Clock::time_point  __c_now = _Clock::now();
-    __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__t - __c_now));
+    wait_for(__lk, __t - _Clock::now());
     return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
 }
 
@@ -427,9 +407,17 @@
                              const chrono::duration<_Rep, _Period>& __d)
 {
     using namespace chrono;
+    if (__d <= __d.zero())
+        return cv_status::timeout;
+    typedef time_point<system_clock, duration<long double, nano> > __sys_tpf;
+    typedef time_point<system_clock, nanoseconds> __sys_tpi;
+    __sys_tpf _Max = __sys_tpi::max();
     system_clock::time_point __s_now = system_clock::now();
     steady_clock::time_point __c_now = steady_clock::now();
-    __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
+    if (_Max - __d > __s_now)
+        __do_timed_wait(__lk, __s_now + __ceil<nanoseconds>(__d));
+    else
+        __do_timed_wait(__lk, __sys_tpi::max());
     return steady_clock::now() - __c_now < __d ? cv_status::no_timeout :
                                                  cv_status::timeout;
 }
diff --git a/include/thread b/include/thread
index d81e853..94e7ab6 100644
--- a/include/thread
+++ b/include/thread
@@ -410,10 +410,20 @@
 sleep_for(const chrono::duration<_Rep, _Period>& __d)
 {
     using namespace chrono;
-    nanoseconds __ns = duration_cast<nanoseconds>(__d);
-    if (__ns < __d)
-        ++__ns;
-    sleep_for(__ns);
+    if (__d > duration<_Rep, _Period>::zero())
+    {
+        _LIBCPP_CONSTEXPR duration<long double> _Max = nanoseconds::max();
+        nanoseconds __ns;
+        if (__d < _Max)
+        {
+            __ns = duration_cast<nanoseconds>(__d);
+            if (__ns < __d)
+                ++__ns;
+        }
+        else
+            __ns = nanoseconds::max();
+        sleep_for(__ns);
+    }
 }
 
 template <class _Clock, class _Duration>
diff --git a/src/condition_variable.cpp b/src/condition_variable.cpp
index 552bce3..de0f6f4 100644
--- a/src/condition_variable.cpp
+++ b/src/condition_variable.cpp
@@ -51,10 +51,22 @@
         __throw_system_error(EPERM,
                             "condition_variable::timed wait: mutex not locked");
     nanoseconds d = tp.time_since_epoch();
+    if (d > nanoseconds(0x59682F000000E941))
+        d = nanoseconds(0x59682F000000E941);
     timespec ts;
     seconds s = duration_cast<seconds>(d);
-    ts.tv_sec = static_cast<decltype(ts.tv_sec)>(s.count());
-    ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
+    typedef decltype(ts.tv_sec) ts_sec;
+    _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
+    if (s.count() < ts_sec_max)
+    {
+        ts.tv_sec = static_cast<ts_sec>(s.count());
+        ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
+    }
+    else
+    {
+        ts.tv_sec = ts_sec_max;
+        ts.tv_nsec = giga::num - 1;
+    }
     int ec = pthread_cond_timedwait(&__cv_, lk.mutex()->native_handle(), &ts);
     if (ec != 0 && ec != ETIMEDOUT)
         __throw_system_error(ec, "condition_variable timed_wait failed");
diff --git a/src/thread.cpp b/src/thread.cpp
index 4445b8d..8747adf 100644
--- a/src/thread.cpp
+++ b/src/thread.cpp
@@ -11,6 +11,7 @@
 #include "exception"
 #include "vector"
 #include "future"
+#include "limits"
 #include <sys/types.h>
 #if !_WIN32
 #if !__sun__ && !__linux__
@@ -83,11 +84,22 @@
 sleep_for(const chrono::nanoseconds& ns)
 {
     using namespace chrono;
-    if (ns >= nanoseconds::zero())
+    if (ns > nanoseconds::zero())
     {
+        seconds s = duration_cast<seconds>(ns);
         timespec ts;
-        ts.tv_sec = static_cast<decltype(ts.tv_sec)>(duration_cast<seconds>(ns).count());
-        ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns - seconds(ts.tv_sec)).count());
+        typedef decltype(ts.tv_sec) ts_sec;
+        _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
+        if (s.count() < ts_sec_max)
+        {
+            ts.tv_sec = static_cast<ts_sec>(s.count());
+            ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count());
+        }
+        else
+        {
+            ts.tv_sec = ts_sec_max;
+            ts.tv_nsec = giga::num - 1;
+        }
         nanosleep(&ts, 0);
     }
 }