diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-13 23:15:16 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-13 23:15:16 +0000 |
commit | 31d92665b434046d054b39485df3d887d43e1cb6 (patch) | |
tree | 8d717a017060417af13aae9fe2e78934bebe0c9f /base | |
parent | d6bebb985c8cb278393beb38059f5df1bece3516 (diff) | |
download | chromium_src-31d92665b434046d054b39485df3d887d43e1cb6.zip chromium_src-31d92665b434046d054b39485df3d887d43e1cb6.tar.gz chromium_src-31d92665b434046d054b39485df3d887d43e1cb6.tar.bz2 |
Make Callback.Reset safe against deleting itself.
BUG=99159
TEST=CallbackTest.ResetRefCountedOwnerOfCallback
Review URL: https://chromiumcodereview.appspot.com/10388060
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142011 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/callback_internal.cc | 4 | ||||
-rw-r--r-- | base/callback_unittest.cc | 32 |
2 files changed, 35 insertions, 1 deletions
diff --git a/base/callback_internal.cc b/base/callback_internal.cc index 760dc90..2dde402 100644 --- a/base/callback_internal.cc +++ b/base/callback_internal.cc @@ -14,8 +14,10 @@ bool CallbackBase::is_null() const { } void CallbackBase::Reset() { - bind_state_ = NULL; polymorphic_invoke_ = NULL; + // NULL the bind_state_ last, since it may be holding the last ref to whatever + // object owns us, and we may be deleted after that. + bind_state_ = NULL; } bool CallbackBase::Equals(const CallbackBase& other) const { diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc index f0f3915..2c2bef1a 100644 --- a/base/callback_unittest.cc +++ b/base/callback_unittest.cc @@ -6,6 +6,7 @@ #include "base/callback.h" #include "base/callback_helpers.h" #include "base/callback_internal.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" @@ -145,5 +146,36 @@ TEST_F(CallbackTest, ResetAndReturn) { ASSERT_TRUE(tfr.cb_already_run); } +class CallbackOwner : public base::RefCounted<CallbackOwner> { + public: + CallbackOwner(bool* deleted) { + callback_ = Bind(&CallbackOwner::Unused, this); + deleted_ = deleted; + } + void Reset() { + callback_.Reset(); + // We are deleted here if no-one else had a ref to us. + } + + private: + friend class base::RefCounted<CallbackOwner>; + virtual ~CallbackOwner() { + *deleted_ = true; + } + void Unused() { + FAIL() << "Should never be called"; + } + + Closure callback_; + bool* deleted_; +}; + +TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) { + bool deleted = false; + CallbackOwner* owner = new CallbackOwner(&deleted); + owner->Reset(); + ASSERT_TRUE(deleted); +} + } // namespace } // namespace base |