From: Andrii Grynenko Date: Sat, 21 Feb 2015 01:22:54 +0000 (-0800) Subject: Fix folly::Singleton DFATAL X-Git-Tag: v0.27.0~21 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=5f2d43af2cd1c51ddef0ee3cf90bad2e5d2bb769;p=folly.git Fix folly::Singleton DFATAL Summary: Previously leak-fatal could never happen because we were incorrectly checking singleton state. Sending this diff to see how many tests will actually fail and potentially fix worst offenders. Test Plan: unit tests Reviewed By: stepan@fb.com Subscribers: trunkagent, folly-diffs@, yfeldblum FB internal diff: D1838405 Signature: t1:1838405:1424478983:94cda86ed57f38b0cf626b74804fbc168d182c66 --- diff --git a/folly/experimental/Singleton-inl.h b/folly/experimental/Singleton-inl.h index 4b109251..302fbc99 100644 --- a/folly/experimental/Singleton-inl.h +++ b/folly/experimental/Singleton-inl.h @@ -85,7 +85,7 @@ TypeDescriptor SingletonHolder::type() { template bool SingletonHolder::hasLiveInstance() { - return state_ == SingletonHolderState::Living; + return !instance_weak_.expired(); } template diff --git a/folly/experimental/test/SingletonTest.cpp b/folly/experimental/test/SingletonTest.cpp index f24ae655..c4adc236 100644 --- a/folly/experimental/test/SingletonTest.cpp +++ b/folly/experimental/test/SingletonTest.cpp @@ -231,6 +231,16 @@ template using SingletonSharedPtrUsage = Singleton ; TEST(Singleton, SharedPtrUsage) { + struct WatchdogHolder { + ~WatchdogHolder() { + if (watchdog) { + LOG(ERROR) << "The following log message with stack trace is expected"; + } + } + + std::shared_ptr watchdog; + }; + auto& vault = *SingletonVault::singleton(); EXPECT_EQ(vault.registeredSingletonCount(), 0); @@ -242,8 +252,15 @@ TEST(Singleton, SharedPtrUsage) { struct ATag {}; SingletonSharedPtrUsage named_watchdog_singleton; + + SingletonSharedPtrUsage watchdog_holder_singleton; + vault.registrationComplete(); + // Initilize holder singleton first, so that it's the last one to be + // destroyed. + watchdog_holder_singleton.get(); + Watchdog* s1 = SingletonSharedPtrUsage::get(); EXPECT_NE(s1, nullptr); @@ -253,10 +270,13 @@ TEST(Singleton, SharedPtrUsage) { EXPECT_EQ(s1, s2); auto weak_s1 = SingletonSharedPtrUsage::get_weak(); + auto shared_s1 = weak_s1.lock(); EXPECT_EQ(shared_s1.get(), s1); EXPECT_EQ(shared_s1.use_count(), 2); + auto old_serial = shared_s1->serial_number; + { auto named_weak_s1 = SingletonSharedPtrUsage::get_weak(); @@ -264,6 +284,10 @@ TEST(Singleton, SharedPtrUsage) { EXPECT_NE(locked.get(), shared_s1.get()); } + // We should release externally locked shared_ptr, otherwise it will be + // considered a leak + watchdog_holder_singleton->watchdog = std::move(shared_s1); + LOG(ERROR) << "The following log message regarding shared_ptr is expected"; { auto start_time = std::chrono::steady_clock::now(); @@ -272,24 +296,9 @@ TEST(Singleton, SharedPtrUsage) { EXPECT_TRUE(duration > std::chrono::seconds{4} && duration < std::chrono::seconds{6}); } - EXPECT_EQ(vault.registeredSingletonCount(), 3); + EXPECT_EQ(vault.registeredSingletonCount(), 4); EXPECT_EQ(vault.livingSingletonCount(), 0); - EXPECT_EQ(shared_s1.use_count(), 1); - EXPECT_EQ(shared_s1.get(), s1); - - auto locked_s1 = weak_s1.lock(); - EXPECT_EQ(locked_s1.get(), s1); - EXPECT_EQ(shared_s1.use_count(), 2); - LOG(ERROR) << "The following log message with stack trace is expected"; - locked_s1.reset(); - EXPECT_EQ(shared_s1.use_count(), 1); - - // Track serial number rather than pointer since the memory could be - // re-used when we create new_s1. - auto old_serial = shared_s1->serial_number; - shared_s1.reset(); - locked_s1 = weak_s1.lock(); EXPECT_TRUE(weak_s1.expired()); auto empty_s1 = SingletonSharedPtrUsage::get_weak(); @@ -299,6 +308,8 @@ TEST(Singleton, SharedPtrUsage) { // Singleton should be re-created only after reenableInstances() was called. Watchdog* new_s1 = SingletonSharedPtrUsage::get(); + // Track serial number rather than pointer since the memory could be + // re-used when we create new_s1. EXPECT_NE(new_s1->serial_number, old_serial); auto new_s1_weak = SingletonSharedPtrUsage::get_weak();