summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-13 23:15:16 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-13 23:15:16 +0000
commit31d92665b434046d054b39485df3d887d43e1cb6 (patch)
tree8d717a017060417af13aae9fe2e78934bebe0c9f
parentd6bebb985c8cb278393beb38059f5df1bece3516 (diff)
downloadchromium_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
-rw-r--r--base/callback_internal.cc4
-rw-r--r--base/callback_unittest.cc32
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