https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99979

            Bug ID: 99979
           Summary: condition_variable_any has wrong behavior if
                    Lock::lock() throws
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redbeard0531 at gmail dot com
  Target Milestone: ---

https://eel.is/c++draft/thread.condvarany.wait says "Postconditions: lock is
locked by the calling thread. […] Remarks: If the function fails to meet the
postcondition, terminate() is invoked […] This can happen if the re-locking of
the mutex throws an exception." This wording was changed in C++14 for
https://cplusplus.github.io/LWG/issue2135, but given that it is borderline
impossible to use a condition_variable[_any] correctly if it doesn't guarantee
relocking, it seems best to do the same in C++11 mode as well.

Unfortunately, std::condition_variable_any::__Unlock::~__Unlock() either
ignores[1] or propagates any exception thrown by lock(), which means that the
postcondition of wait() may not be fulfilled. I think the correct behavior
would be to remove the noexcept(false), allowing the destructor's default
noexecpt to apply, and just unconditionally call _M_lock.lock() without any
try/catch.

[1] It ignores if std::uncaught_exception() returns true. I'm not 100% sure why
that dispatch is there. It seems like it may be trying to detect if
_M_cond.wait() threw, but a) that is noexcept and b) that doesn't work
correctly if some thread waits on a condvar inside a destructor that is
triggered during exception unwinding (this is why std::uncaught_exceptions()
was introduced).

Reply via email to