From ae645471f62870fbe4d09eaa82e9043ffe7284b8 Mon Sep 17 00:00:00 2001 From: "cpu@google.com" Date: Fri, 1 Aug 2008 03:06:25 +0000 Subject: Adds new class AtExitManager which manages the dtors of all singletons. - Previously this job was done by the CRT's atexit() which runs later than we want and under the loader lock. - Had to modify most main() functions for the testing executables so we don't trigger leak detectors. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219 0039d316-1c4b-4281-b951-d872f2087c98 --- base/at_exit.cc | 87 ++++++++++++++++++++++++++++ base/at_exit.h | 80 +++++++++++++++++++++++++ base/at_exit_unittest.cc | 82 ++++++++++++++++++++++++++ base/build/base.vcproj | 14 ++++- base/build/base_unittests.vcproj | 4 ++ base/run_all_perftests.cc | 5 ++ base/run_all_unittests.cc | 5 ++ base/singleton.h | 55 ++++++------------ base/singleton_dll_unittest.cc | 10 ++++ chrome/app/chrome_main.cc | 4 ++ chrome/app/main.cc | 4 ++ chrome/common/ipc_tests.cc | 5 ++ chrome/installer/util/run_all_unittests.cc | 6 ++ chrome/test/reliability/run_all_unittests.cc | 5 ++ chrome/test/ui/run_all_unittests.cc | 5 ++ chrome/test/unit/run_all_unittests.cc | 5 ++ webkit/tools/test_shell/run_all_tests.cc | 5 ++ webkit/tools/test_shell/test_shell_main.cc | 4 ++ 18 files changed, 345 insertions(+), 40 deletions(-) create mode 100644 base/at_exit.cc create mode 100644 base/at_exit.h create mode 100644 base/at_exit_unittest.cc diff --git a/base/at_exit.cc b/base/at_exit.cc new file mode 100644 index 0000000..c43e9ac --- /dev/null +++ b/base/at_exit.cc @@ -0,0 +1,87 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "base/at_exit.h" +#include "base/logging.h" + +namespace { + +std::stack* g_atexit_queue = NULL; +Lock* g_atexit_lock = NULL; + +void ProcessCallbacks() { + if (!g_atexit_queue) + return; + base::AtExitCallbackType func = NULL; + while(!g_atexit_queue->empty()) { + func = g_atexit_queue->top(); + g_atexit_queue->pop(); + if (func) + func(); + } +} + +} // namespace + +namespace base { + +AtExitManager::AtExitManager() { + DCHECK(NULL == g_atexit_queue); + DCHECK(NULL == g_atexit_lock); + g_atexit_lock = &lock_; + g_atexit_queue = &atexit_queue_; +} + +AtExitManager::~AtExitManager() { + AutoLock lock(lock_); + ProcessCallbacks(); + g_atexit_queue = NULL; +} + +void AtExitManager::RegisterCallback(AtExitCallbackType func) { + DCHECK(NULL != g_atexit_queue); + DCHECK(NULL != g_atexit_lock); + if (!g_atexit_lock) + return; + AutoLock lock(*g_atexit_lock); + if (g_atexit_queue) + g_atexit_queue->push(func); +} + +// Calls the functions registered with AtExit in LIFO order. +void AtExitManager::ProcessCallbacksNow() { + DCHECK(NULL != g_atexit_lock); + if (!g_atexit_lock) + return; + AutoLock lock(*g_atexit_lock); + DCHECK(NULL != g_atexit_queue); + ProcessCallbacks(); +} + +} // namespace base diff --git a/base/at_exit.h b/base/at_exit.h new file mode 100644 index 0000000..8b9f946 --- /dev/null +++ b/base/at_exit.h @@ -0,0 +1,80 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef BASE_AT_EXIT_H__ +#define BASE_AT_EXIT_H__ + +#include + +#include "base/basictypes.h" +#include "base/lock.h" + +namespace base { + +typedef void (*AtExitCallbackType)(); + +// This class provides a facility similar to the CRT atexit(), except that +// we control when the callbacks are executed. Under Windows for a DLL they +// happen at a really bad time and under the loader lock. This facility is +// mostly used by base::Singleton. +// +// The usage is simple. Early in the main() or WinMain() scope create an +// AtExitManager object on the stack: +// int main(...) { +// base::AtExitManager exit_manager; +// +// } +// When the exit_manager object goes out of scope, all the registered +// callbacks and singleton destructors will be called. + +class AtExitManager { + public: + AtExitManager(); + + // The dtor calls all the registered callbacks. Do not try to register more + // callbacks after this point. + ~AtExitManager(); + + // Registers the specified function to be called at exit. The prototype of + // the callback function is void func(). + static void RegisterCallback(AtExitCallbackType func); + + // Calls the functions registered with RegisterCallback in LIFO order. It + // is possible to register new callbacks after calling this function. + static void ProcessCallbacksNow(); + + private: + Lock lock_; + std::stack atexit_queue_; + DISALLOW_EVIL_CONSTRUCTORS(AtExitManager); +}; + +} // namespace base + +#endif // BASE_AT_EXIT_H__ diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc new file mode 100644 index 0000000..692ce66 --- /dev/null +++ b/base/at_exit_unittest.cc @@ -0,0 +1,82 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "base/at_exit.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +int g_test_counter_1 = 0; +int g_test_counter_2 = 0; + +void IncrementTestCounter1() { + ++g_test_counter_1; +} + +void IncrementTestCounter2() { + ++g_test_counter_2; +} + +void ZeroTestCounters() { + g_test_counter_1 = 0; + g_test_counter_2 = 0; +} + +void ExpectCounter1IsZero() { + EXPECT_EQ(0, g_test_counter_1); +} + +} // namespace + +TEST(AtExitTest, Basic) { + ZeroTestCounters(); + base::AtExitManager::RegisterCallback(&IncrementTestCounter1); + base::AtExitManager::RegisterCallback(&IncrementTestCounter2); + base::AtExitManager::RegisterCallback(&IncrementTestCounter1); + + EXPECT_EQ(0, g_test_counter_1); + EXPECT_EQ(0, g_test_counter_2); + base::AtExitManager::ProcessCallbacksNow(); + EXPECT_EQ(2, g_test_counter_1); + EXPECT_EQ(1, g_test_counter_2); +} + +TEST(AtExitTest, LIFOOrder) { + ZeroTestCounters(); + base::AtExitManager::RegisterCallback(&IncrementTestCounter1); + base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero); + base::AtExitManager::RegisterCallback(&IncrementTestCounter2); + + EXPECT_EQ(0, g_test_counter_1); + EXPECT_EQ(0, g_test_counter_2); + base::AtExitManager::ProcessCallbacksNow(); + EXPECT_EQ(1, g_test_counter_1); + EXPECT_EQ(1, g_test_counter_2); +} diff --git a/base/build/base.vcproj b/base/build/base.vcproj index dd129a5..e4d47856 100644 --- a/base/build/base.vcproj +++ b/base/build/base.vcproj @@ -122,6 +122,14 @@ + + + + @@ -162,15 +170,15 @@ > + + diff --git a/base/run_all_perftests.cc b/base/run_all_perftests.cc index 4ef7494..78eeb37 100644 --- a/base/run_all_perftests.cc +++ b/base/run_all_perftests.cc @@ -29,12 +29,17 @@ #include +#include "base/at_exit.h" #include "base/command_line.h" #include "base/perftimer.h" #include "base/string_util.h" #include "base/test_suite.h" int main(int argc, char** argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + // Initialize the perf timer log std::string log_file = WideToUTF8(CommandLine().GetSwitchValue(L"log-file")); diff --git a/base/run_all_unittests.cc b/base/run_all_unittests.cc index 69b2d3f..299b1c1 100644 --- a/base/run_all_unittests.cc +++ b/base/run_all_unittests.cc @@ -27,8 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "base/at_exit.h" #include "base/test_suite.h" int main(int argc, char** argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + return TestSuite(argc, argv).Run(); } diff --git a/base/singleton.h b/base/singleton.h index 47c0c1d..7df5335 100644 --- a/base/singleton.h +++ b/base/singleton.h @@ -34,6 +34,7 @@ #include +#include "base/at_exit.h" #include "base/lock.h" #include "base/singleton_internal.h" @@ -44,7 +45,7 @@ #endif // WIN32 // Default traits for Singleton. Calls operator new and operator delete on -// the object. Registers automatic deletion at library unload or process exit. +// the object. Registers automatic deletion at process exit. // Overload if you need arguments or another memory allocation function. template struct DefaultSingletonTraits { @@ -60,8 +61,8 @@ struct DefaultSingletonTraits { delete x; } - // Set to true to automatically register deletion of the object on library - // unload or process exit. + // Set to true to automatically register deletion of the object on process + // exit. See below for the required call that makes this happen. static const bool kRegisterAtExit = true; // Note: Only apply on Windows. Has *no effect* on other platform. @@ -75,8 +76,8 @@ struct DefaultSingletonTraits { // The Singleton class manages a single // instance of Type which will be created on first use and will be destroyed at -// library unload (or on normal process exit). The Trait::Delete function will -// not be called on abnormal process exit. +// normal process exit). The Trait::Delete function will not be called on +// abnormal process exit. // // DifferentiatingType is used as a key to differentiate two different // singletons having the same memory allocation functions but serving a @@ -101,11 +102,15 @@ struct DefaultSingletonTraits { // RAE = kRegisterAtExit // // On every platform, if Traits::RAE is true, the singleton will be destroyed at -// library unload or process exit. if Traits::RAE is false, the singleton will -// not be freed at library unload or process exit, thus the singleton will be -// leaked if it is ever accessed. Traits::RAE shouldn't be false unless -// absolutely necessary. Remember that the heap where the object is allocated -// may be destroyed by the CRT anyway. +// process exit. More precisely it uses base::AtExitManager which requires an +// object of this type to be instanciated. AtExitManager mimics the semantics +// of atexit() such as LIFO order but under Windows is safer to call. For more +// information see at_exit.h. +// +// If Traits::RAE is false, the singleton will not be freed at process exit, +// thus the singleton will be leaked if it is ever accessed. Traits::RAE +// shouldn't be false unless absolutely necessary. Remember that the heap where +// the object is allocated may be destroyed by the CRT anyway. // // On Windows, now the fun begins. Traits::New() may be called more than once // concurrently, but no user will gain access to the object until the winning @@ -231,16 +236,8 @@ class Singleton // Race condition, discard the temporary value. Traits::Delete(value); } else { - // Got it, register destruction at unload. atexit() is called on library - // unload. It is assumed that atexit() is itself thread safe. It is also - // assumed that registered functions by atexit are called in a thread - // safe manner. At least on Windows, they are called with the loader - // lock held. On Windows, the CRT use a structure similar to - // std::map> so the right - // functions are called on library unload, independent of having a DLL - // CRT or a static CRT or even both. if (Traits::kRegisterAtExit) - atexit(&OnExit); + base::AtExitManager::RegisterCallback(&OnExit); } } #endif // WIN32 @@ -249,27 +246,11 @@ class Singleton static void SafeConstruct() { instance_ = Traits::New(); - // Porting note: this code depends on some properties of atexit which are - // not guaranteed by the standard: - // - atexit must be thread-safe: its internal manipulation of the list of - // registered functions must be tolerant of multiple threads attempting - // to register exit routines simultaneously. - // - exit routines must run when the executable module that contains them - // is unloaded. For routines in by dynamically-loaded modules, this - // may be sooner than process termination. - // - atexit should support an arbitrary number of registered exit - // routines, or at least should support more routines than will - // actually be registered (the standard only requires 32). - // The atexit implementations in contemporary versions of Mac OS X, glibc, - // and the Windows C runtime provide these capabilities. To port to other - // systems with less-advanced (even though still standard-conforming) - // atexit implmentations, consider alternatives such as __cxa_atexit or - // custom termination sections. if (Traits::kRegisterAtExit) - atexit(OnExit); + base::AtExitManager::RegisterCallback(OnExit); } - // Adapter function for use with atexit(). + // Adapter function for use with AtExit(). static void OnExit() { if (!instance_) return; diff --git a/base/singleton_dll_unittest.cc b/base/singleton_dll_unittest.cc index c663db3..4e0ec3a 100644 --- a/base/singleton_dll_unittest.cc +++ b/base/singleton_dll_unittest.cc @@ -28,16 +28,26 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "base/singleton_dll_unittest.h" +#include "base/at_exit.h" #include "base/logging.h" +namespace { + +base::AtExitManager* g_exit_manager = NULL; + +} // namespace + BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) { switch (reason_for_call) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(module); + g_exit_manager = new base::AtExitManager(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: + break; case DLL_PROCESS_DETACH: + delete g_exit_manager; break; } return TRUE; diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc index 54cb57c..a6f8091 100644 --- a/chrome/app/chrome_main.cc +++ b/chrome/app/chrome_main.cc @@ -32,6 +32,7 @@ #include #include +#include "base/at_exit.h" #include "base/command_line.h" #include "base/icu_util.h" #include "base/message_loop.h" @@ -140,6 +141,9 @@ DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance, _CrtSetReportMode(_CRT_ASSERT, 0); #endif + // The exit manager is in charge of calling the dtors of singleton objects. + base::AtExitManager exit_manager; + // Register the invalid param handler and pure call handler to be able to // notify breakpad when it happens. _set_invalid_parameter_handler(InvalidParameter); diff --git a/chrome/app/main.cc b/chrome/app/main.cc index cbcfdee..ab2848b 100644 --- a/chrome/app/main.cc +++ b/chrome/app/main.cc @@ -30,6 +30,7 @@ #include #include +#include "base/at_exit.h" #include "base/base_switches.h" #include "base/command_line.h" #include "base/debug_on_start.h" @@ -43,6 +44,9 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev_instance, wchar_t* command_line, int show_command) { + // The exit manager is in charge of calling the dtors of singletons. + base::AtExitManager exit_manager; + google_update::GoogleUpdateClient client; // Note that std::wstring and CommandLine got linked anyway because of diff --git a/chrome/common/ipc_tests.cc b/chrome/common/ipc_tests.cc index a9d998c..dbcd33d 100644 --- a/chrome/common/ipc_tests.cc +++ b/chrome/common/ipc_tests.cc @@ -34,6 +34,7 @@ #include "chrome/common/ipc_tests.h" +#include "base/at_exit.h" #include "base/base_switches.h" #include "base/command_line.h" #include "base/debug_on_start.h" @@ -400,6 +401,10 @@ HANDLE SpawnChild(ChildType child_type) { } int main(int argc, char** argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + MessageLoop main_message_loop; // suppress standard crash dialogs and such unless a debugger is present. diff --git a/chrome/installer/util/run_all_unittests.cc b/chrome/installer/util/run_all_unittests.cc index 69b2d3f..f38f05b 100644 --- a/chrome/installer/util/run_all_unittests.cc +++ b/chrome/installer/util/run_all_unittests.cc @@ -27,8 +27,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "base/at_exit.h" #include "base/test_suite.h" int main(int argc, char** argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + return TestSuite(argc, argv).Run(); } diff --git a/chrome/test/reliability/run_all_unittests.cc b/chrome/test/reliability/run_all_unittests.cc index a5d3da3..cfe0a29 100644 --- a/chrome/test/reliability/run_all_unittests.cc +++ b/chrome/test/reliability/run_all_unittests.cc @@ -27,8 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "base/at_exit.h" #include "chrome/test/reliability/reliability_test_suite.h" int main(int argc, char **argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + return ReliabilityTestSuite(argc, argv).Run(); } diff --git a/chrome/test/ui/run_all_unittests.cc b/chrome/test/ui/run_all_unittests.cc index 737a7be..8d1307772 100644 --- a/chrome/test/ui/run_all_unittests.cc +++ b/chrome/test/ui/run_all_unittests.cc @@ -27,9 +27,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "base/at_exit.h" #include "chrome/test/ui/ui_test_suite.h" int main(int argc, char **argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + Thread::SetThreadName("Tests_Main", GetCurrentThreadId()); return UITestSuite(argc, argv).Run(); } diff --git a/chrome/test/unit/run_all_unittests.cc b/chrome/test/unit/run_all_unittests.cc index f8d6fea..f52bd78 100644 --- a/chrome/test/unit/run_all_unittests.cc +++ b/chrome/test/unit/run_all_unittests.cc @@ -27,8 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "base/at_exit.h" #include "chrome/test/unit/chrome_test_suite.h" int main(int argc, char **argv) { + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + return ChromeTestSuite(argc, argv).Run(); } diff --git a/webkit/tools/test_shell/run_all_tests.cc b/webkit/tools/test_shell/run_all_tests.cc index 05cdc43..3c4148d 100644 --- a/webkit/tools/test_shell/run_all_tests.cc +++ b/webkit/tools/test_shell/run_all_tests.cc @@ -33,6 +33,7 @@ #include #include +#include "base/at_exit.h" #include "base/icu_util.h" #include "base/message_loop.h" #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" @@ -50,6 +51,10 @@ const char* TestShellTest::kJavascriptDelayExitScript = ""; int main(int argc, char* argv[]) { + // Some unittests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; + TestShell::InitLogging(true); // suppress error dialogs // Initialize test shell in non-interactive mode, which will let us load one diff --git a/webkit/tools/test_shell/test_shell_main.cc b/webkit/tools/test_shell/test_shell_main.cc index 468ec36..4b1940e 100644 --- a/webkit/tools/test_shell/test_shell_main.cc +++ b/webkit/tools/test_shell/test_shell_main.cc @@ -34,6 +34,7 @@ #include #include +#include "base/at_exit.h" #include "base/basictypes.h" #include "base/command_line.h" #include "base/event_recorder.h" @@ -136,6 +137,9 @@ int main(int argc, char* argv[]) _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); #endif + // Some tests may use base::Singleton<>, thus we need to instanciate + // the AtExitManager or else we will leak objects. + base::AtExitManager at_exit_manager; CommandLine parsed_command_line; if (parsed_command_line.HasSwitch(test_shell::kStartupDialog)) -- cgit v1.1