diff options
| author | vladlosev <vladlosev@8415998a-534a-0410-bf83-d39667b30386> | 2011-10-24 23:41:07 +0000 | 
|---|---|---|
| committer | vladlosev <vladlosev@8415998a-534a-0410-bf83-d39667b30386> | 2011-10-24 23:41:07 +0000 | 
| commit | 9bcb5f9146db42bc38b6bb744fb0cf518a0205be (patch) | |
| tree | 25eaddb193823d54b9dce3878b0f32d2eba6739a /include | |
| parent | 4d60a596b4135c5a7e21ef7b4fe24a5c90329e0f (diff) | |
| download | googletest-9bcb5f9146db42bc38b6bb744fb0cf518a0205be.tar.gz googletest-9bcb5f9146db42bc38b6bb744fb0cf518a0205be.tar.bz2 googletest-9bcb5f9146db42bc38b6bb744fb0cf518a0205be.zip  | |
Fixes a lock reentrancy when destroying a mock causes destruction of another mock (issue 79) (by Aaron Jacobs).
Diffstat (limited to 'include')
| -rw-r--r-- | include/gmock/gmock-spec-builders.h | 21 | 
1 files changed, 18 insertions, 3 deletions
diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 1953e43a..36c47d67 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1475,12 +1475,27 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {    virtual void ClearDefaultActionsLocked()        GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {      g_gmock_mutex.AssertHeld(); + +    // Deleting our default actions may trigger other mock objects to be +    // deleted, for example if an action contains a reference counted smart +    // pointer to that mock object, and that is the last reference. So if we +    // delete our actions within the context of the global mutex we may deadlock +    // when this method is called again. Instead, make a copy of the set of +    // actions to delete, clear our set within the mutex, and then delete the +    // actions outside of the mutex. +    UntypedOnCallSpecs specs_to_delete; +    untyped_on_call_specs_.swap(specs_to_delete); + +    g_gmock_mutex.Unlock();      for (UntypedOnCallSpecs::const_iterator it = -             untyped_on_call_specs_.begin(); -         it != untyped_on_call_specs_.end(); ++it) { +             specs_to_delete.begin(); +         it != specs_to_delete.end(); ++it) {        delete static_cast<const OnCallSpec<F>*>(*it);      } -    untyped_on_call_specs_.clear(); + +    // Lock the mutex again, since the caller expects it to be locked when we +    // return. +    g_gmock_mutex.Lock();    }   protected:  | 
