[libcxx-dev] system_error in shared_future::wait_for

b via libcxx-dev libcxx-dev at lists.llvm.org
Tue May 14 08:49:40 PDT 2019

Hello everyone,

I am new to this list. I am writing because I think I might have caught a bug in libc++. What I hope to get is a quick assessment of my issue so that I know if I should file this as a bug or some hints in how I should proceed to gather more information or even rectify the issue on my end.

The issue I am seeing popped up in a macOS project (Xcode 10.2.1) I am working on but I was able to condense it into a very small test program, see below for the code.

The issue presents itself as a crash in shared_future::wait_for due to an uncatchable exception. The crash does not occur immediately but only after a (huge) number of calls. Console output in Xcode reads  "libc++abi.dylib: terminating with uncaught exception of type std::__1::system_error: condition_variable timed_wait failed: Invalid argument“. See backtrace further down for details. Unfortunately I cannot step into code of the method where the exception originates which is condition_variable::__do_timed_wait. I browsed the code in the libcxx repository and found that the error must be the result code EINVAL from a call to pthread_cond_timedwait.

The interesting bit is that the issue can be reproduced in each test run within (mostly) less than 10 minutes on an iMac18,3/i7 and on a MacBookPro15,1/i7 but never on a MacBookPro15,2/i5. I only have one machine of each of those available so I cannot be sure how these results hold up.

1. Is there something fundamentally wrong with my code, i.e. how I use the shared_future?

2. Is this likely to be a bug in libc++ or is it more likely to be an issue with the BSD level API and/or the hardware? In case of the latter option where should I seek contact?

3. I would like to be able to step into the code for condition_variable::__do_timed_wait and get the debugger info for the local variables. Would this be simply a matter of pulling the libcxx repository, building and linking it? I am not a command line compilation guy so I was hoping for some good documentation on how to do this with and for Xcode. However, if must be, I am willing to accept my fate.


Notes on the code below:

- The production code does not call sharedFuture.wait_for with 100ns. The production code currently uses 1ms which makes the issue pop up much less often, I saw half a day and three days, for example. 100ns has proven to trigger the exception much more often, that’s all.
- FWIW, the same exception is thrown with shared_future::wait_until(steadyClockTimePoint), so steady clock accuracy does not seem to help.


#include <future>
#include <thread>

using namespace std;

int main(int argc, const char * argv[])
   promise<void> thePromise = promise<void> {};
   shared_future<void> sharedFuture = thePromise.get_future().share();
   thread anotherThread = thread( [sharedFuture]
      int debugCount = 0;
      while (sharedFuture.wait_for(100ns) == future_status::timeout)
   return 0;


thread #1, queue = 'com.apple.main-thread'
    frame #0: 0x00007fff7f7fb86a libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00000001003d11b2 libsystem_pthread.dylib`_pthread_cond_wait + 722
    frame #2: 0x00007fff7c6d2a0a libc++.1.dylib`std::__1::condition_variable::wait(std::__1::unique_lock<std::__1::mutex>&) + 18
    frame #3: 0x00007fff7c6db96b libc++.1.dylib`std::__1::__assoc_sub_state::__sub_wait(std::__1::unique_lock<std::__1::mutex>&) + 45
    frame #4: 0x00007fff7c6db9d4 libc++.1.dylib`std::__1::__assoc_sub_state::wait() + 46
    frame #5: 0x0000000100000aa8 shared_future_wait_for`std::__1::shared_future<void>::wait(this=0x00007ffeefbff460) const at future:2561:34
    frame #6: 0x0000000100000932 shared_future_wait_for`main(argc=1, argv=0x00007ffeefbff4a0) at main.cpp:34:17
    frame #7: 0x00007fff7f6c33d5 libdyld.dylib`start + 1
* thread #2, stop reason = signal SIGABRT
    frame #0: 0x00007fff7f7fe2c6 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00000001003d080d libsystem_pthread.dylib`pthread_kill + 284
    frame #2: 0x00007fff7f7686a6 libsystem_c.dylib`abort + 127
    frame #3: 0x00007fff7c721641 libc++abi.dylib`abort_message + 231
    frame #4: 0x00007fff7c7217c7 libc++abi.dylib`default_terminate_handler() + 243
    frame #5: 0x00007fff7de97eeb libobjc.A.dylib`_objc_terminate() + 105
    frame #6: 0x00007fff7c72d19e libc++abi.dylib`std::__terminate(void (*)()) + 8
    frame #7: 0x00007fff7c72d213 libc++abi.dylib`std::terminate() + 51
    frame #8: 0x00007fff7c6daeeb libc++.1.dylib`__clang_call_terminate + 11
    frame #9: 0x00007fff7c6d2b73 libc++.1.dylib`std::__1::condition_variable::__do_timed_wait(std::__1::unique_lock<std::__1::mutex>&, std::__1::chrono::time_point<std::__1::chrono::system_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >) + 159
  * frame #10: 0x00000001000020d3 shared_future_wait_for`std::__1::cv_status std::__1::condition_variable::wait_for<long long, std::__1::ratio<1l, 1000000000l> >(this=0x0000000100646e88, __lk=0x000070000a51bd48, __d=0x000070000a51bce0) at __mutex_base:416:9
    frame #11: 0x0000000100001e67 shared_future_wait_for`std::__1::cv_status std::__1::condition_variable::wait_until<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >(this=0x0000000100646e88, __lk=0x000070000a51bd48, __t=0x000070000a51bd98) at __mutex_base:384:5
    frame #12: 0x0000000100001cc2 shared_future_wait_for`std::__1::future_status std::__1::__assoc_sub_state::wait_until<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >(this=0x0000000100646e30, __abs_time=0x000070000a51bd98) const at future:604:15
    frame #13: 0x0000000100001bdf shared_future_wait_for`std::__1::future_status std::__1::__assoc_sub_state::wait_for<long long, std::__1::ratio<1l, 1000000000l> >(this=0x0000000100646e30, __rel_time=0x000070000a51be68) const at future:615:12
    frame #14: 0x0000000100001a60 shared_future_wait_for`std::__1::future_status std::__1::shared_future<void>::wait_for<long long, std::__1::ratio<1l, 1000000000l> >(this=0x00000001006431b8, __rel_time=0x000070000a51be68) const at future:2566:31
    frame #15: 0x00000001000018c0 shared_future_wait_for`main::$_0::operator(this=0x00000001006431b8)() const at main.cpp:18:30
    frame #16: 0x000000010000182d shared_future_wait_for`decltype(__f=0x00000001006431b8)()) std::__1::__invoke<main::$_0>(main::$_0&&) at type_traits:4339:1
    frame #17: 0x0000000100001795 shared_future_wait_for`void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, main::$_0>(__t=size=2, (null)=__tuple_indices<> @ 0x000070000a51beb8) at thread:342:5
    frame #18: 0x0000000100000f66 shared_future_wait_for`void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, main::$_0> >(__vp=0x00000001006431b0) at thread:352:5
    frame #19: 0x00000001003cddc3 libsystem_pthread.dylib`_pthread_body + 126
    frame #20: 0x00000001003d0e8d libsystem_pthread.dylib`_pthread_start + 66
    frame #21: 0x00000001003cce11 libsystem_pthread.dylib`thread_start + 13
  thread #3
    frame #0: 0x00007fff7f7f9bfe libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00000001003cd0ea libsystem_pthread.dylib`_pthread_wqthread + 634
    frame #2: 0x00000001003cce01 libsystem_pthread.dylib`start_wqthread + 13

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libcxx-dev/attachments/20190514/67236675/attachment.html>

More information about the libcxx-dev mailing list