diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-21 20:41:47 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-21 20:41:47 +0000 |
commit | dcc6933f480397af42af5fa08d40475c13d266e8 (patch) | |
tree | ee6e4ca772e87f9ce27f60315895e7d9392d814e | |
parent | 363dc7f1f2025475b418bfee73efe3030d9b1313 (diff) | |
download | chromium_src-dcc6933f480397af42af5fa08d40475c13d266e8.zip chromium_src-dcc6933f480397af42af5fa08d40475c13d266e8.tar.gz chromium_src-dcc6933f480397af42af5fa08d40475c13d266e8.tar.bz2 |
ThreadRestrictions: leak the thread local variable
LazyInstances are destroyed by the AtExitManager, but we have
threads that outlive the AtExitManager that could potentially
access this.
Review URL: http://codereview.chromium.org/3956003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63410 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/lazy_instance.cc | 3 | ||||
-rw-r--r-- | base/lazy_instance.h | 16 | ||||
-rw-r--r-- | base/lazy_instance_unittest.cc | 43 | ||||
-rw-r--r-- | base/thread_restrictions.cc | 8 |
4 files changed, 65 insertions, 5 deletions
diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc index 957482c..eb71061 100644 --- a/base/lazy_instance.cc +++ b/base/lazy_instance.cc @@ -37,7 +37,8 @@ void LazyInstanceHelper::CompleteInstance(void* instance, void (*dtor)(void*)) { base::subtle::Release_Store(&state_, STATE_CREATED); // Make sure that the lazily instantiated object will get destroyed at exit. - base::AtExitManager::RegisterCallback(dtor, instance); + if (dtor) + base::AtExitManager::RegisterCallback(dtor, instance); } } // namespace base diff --git a/base/lazy_instance.h b/base/lazy_instance.h index 52a5124..ebf1e73 100644 --- a/base/lazy_instance.h +++ b/base/lazy_instance.h @@ -55,6 +55,22 @@ struct DefaultLazyInstanceTraits { } }; +template <typename Type> +struct LeakyLazyInstanceTraits { + static Type* New(void* instance) { + return DefaultLazyInstanceTraits<Type>::New(instance); + } + // Rather than define an empty Delete function, we make Delete itself + // a null pointer. This allows us to completely sidestep registering + // this object with an AtExitManager, which allows you to use + // LeakyLazyInstanceTraits in contexts where you don't have an + // AtExitManager. + static void (*Delete)(void* instance); +}; + +template <typename Type> +void (*LeakyLazyInstanceTraits<Type>::Delete)(void* instance) = NULL; + // We pull out some of the functionality into a non-templated base, so that we // can implement the more complicated pieces out of line in the .cc file. class LazyInstanceHelper { diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc index d55f664..1731381 100644 --- a/base/lazy_instance_unittest.cc +++ b/base/lazy_instance_unittest.cc @@ -95,3 +95,46 @@ TEST(LazyInstanceTest, ConstructorThreadSafety) { EXPECT_EQ(1, SlowConstructor::constructed); } } + +namespace { + +// DeleteLogger is an object which sets a flag when it's destroyed. +// It accepts a bool* and sets the bool to true when the dtor runs. +class DeleteLogger { + public: + DeleteLogger() : deleted_(NULL) {} + ~DeleteLogger() { *deleted_ = true; } + + void SetDeletedPtr(bool* deleted) { + deleted_ = deleted; + } + + private: + bool* deleted_; +}; + +} // anonymous namespace + +TEST(LazyInstanceTest, LeakyLazyInstance) { + // Check that using a plain LazyInstance causes the dtor to run + // when the AtExitManager finishes. + bool deleted1 = false; + { + base::ShadowingAtExitManager shadow; + static base::LazyInstance<DeleteLogger> test(base::LINKER_INITIALIZED); + test.Get().SetDeletedPtr(&deleted1); + } + EXPECT_TRUE(deleted1); + + // Check that using a *leaky* LazyInstance makes the dtor not run + // when the AtExitManager finishes. + bool deleted2 = false; + { + base::ShadowingAtExitManager shadow; + static base::LazyInstance<DeleteLogger, + base::LeakyLazyInstanceTraits<DeleteLogger> > + test(base::LINKER_INITIALIZED); + test.Get().SetDeletedPtr(&deleted2); + } + EXPECT_FALSE(deleted2); +} diff --git a/base/thread_restrictions.cc b/base/thread_restrictions.cc index 5be8ad7..1ee8eee 100644 --- a/base/thread_restrictions.cc +++ b/base/thread_restrictions.cc @@ -11,15 +11,15 @@ #include "base/logging.h" #include "base/thread_local.h" +namespace base { + namespace { -static base::LazyInstance<base::ThreadLocalBoolean> - g_io_disallowed(base::LINKER_INITIALIZED); +LazyInstance<ThreadLocalBoolean, LeakyLazyInstanceTraits<ThreadLocalBoolean> > + g_io_disallowed(LINKER_INITIALIZED); } // anonymous namespace -namespace base { - // static void ThreadRestrictions::SetIOAllowed(bool allowed) { g_io_disallowed.Get().Set(!allowed); |