[Boost-bugs] [Boost C++ Libraries] #9535: Missing exception safety might result in crash

Subject: [Boost-bugs] [Boost C++ Libraries] #9535: Missing exception safety might result in crash
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2013-12-30 11:06:56


#9535: Missing exception safety might result in crash
------------------------------+----------------------
 Reporter: anonymous | Owner: anthonyw
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: thread
  Version: Boost 1.55.0 | Severity: Problem
 Keywords: |
------------------------------+----------------------
 As I was curious as to how boost::wait_for_any is implemented, and I think
 I found a little flaw in the future_waiter class in
 boost/thread/future.hpp ( which the documentation incorrectly lists as
 <boost/thread/futures.hpp> ):

 The future_waiter class registers it's condition variable in the add
 function

 {{{
             template<typename F>
             void add(F& f)
             {
                 if(f.future_)
                 {
 futures.push_back(registered_waiter(f.future_,f.future_->register_external_waiter(cv),future_count));
                 }
                 ++future_count;
             }
 }}}

 and unregisters it in the destructor

 {{{
             ~future_waiter()
             {
                 for(count_type i=0;i<futures.size();++i)
                 {
 futures[i].future_->remove_external_waiter(futures[i].wait_iterator);
                 }
             }
 }}}
 However, if the program encounters an out-of-memory condition during it's
 call to push_back in add(), the registered_waiter is not stored in the
 vector und thus is not unregistered in the destructor, so as soon as the
 future readies up, it calls notify_all on a dangling pointer, resulting in
 a crash. I was able to successfully construct this scenario by overloading
 operator new() using GCC on a unix-like OS.

 I suggest adding a mechanism to unregister the waiter in case of an
 exception. Changing the add function to the following fixed it for me:

 {{{
             template<typename F>
             void add(F& f)
             {
                 if(f.future_)
                 {
                     registered_waiter
 waiter(f.future_,f.future_->register_external_waiter(cv),future_count);
                     try {
                         futures.push_back(waiter);
                     } catch(...)
 {f.future_->remove_external_waiter(waiter.wait_iterator); throw;}
                 }
                 ++future_count;
             }
 }}}
 As you see, I have just introduced a local variable and a try-catch block.
 There could be more elegant solutions, but this was the first one that
 came to mind.

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/9535>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:15 UTC