From 6dcd46c8d21708451bc2f25128816037f8129ceb Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Sat, 18 Apr 2009 01:24:27 +0000 Subject: Fix initialization ordering problem in logging code. Based on patch from Wink Saville. --- CONTRIBUTORS.txt | 2 ++ src/google/protobuf/stubs/common.cc | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 0ad37d93..b01fed62 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -63,3 +63,5 @@ Patch contributors: * Fixed warnings about generated constructors not explicitly initializing all fields (only present with certain compiler settings). * Added generation of field number constants. + Wink Saville + * Fixed initialization ordering problem in logging code. diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc index 54f31ba4..385ea8ae 100644 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -113,7 +113,27 @@ void NullLogHandler(LogLevel level, const char* filename, int line, static LogHandler* log_handler_ = &DefaultLogHandler; static int log_silencer_count_ = 0; -static Mutex log_silencer_count_mutex_; + +// Mutex which protects log_silencer_count_. We provide a static function to +// get it so that it is initialized on first use, which be during +// initialization time. If we just allocated it as a global variable, it might +// not be initialized before someone tries to use it. +static Mutex* LogSilencerMutex() { + static Mutex* log_silencer_count_mutex_ = new Mutex; + return log_silencer_count_mutex_; +} + +// Forces the above mutex to be initialized during startup. This way we don't +// have to worry about the initialization itself being thread-safe, since no +// threads should exist yet at startup time. (Otherwise we'd have no way to +// make things thread-safe here because we'd need a Mutex for that, and we'd +// have no way to construct one safely!) +static struct LogSilencerMutexInitializer { + LogSilencerMutexInitializer() { + LogSilencerMutex(); + } +} log_silencer_mutex_initializer; + static string SimpleCtoa(char c) { return string(1, c); } @@ -140,7 +160,7 @@ void LogMessage::Finish() { bool suppress = false; if (level_ != LOGLEVEL_FATAL) { - MutexLock lock(&internal::log_silencer_count_mutex_); + MutexLock lock(internal::LogSilencerMutex()); suppress = internal::log_silencer_count_ > 0; } @@ -173,12 +193,12 @@ LogHandler* SetLogHandler(LogHandler* new_func) { } LogSilencer::LogSilencer() { - MutexLock lock(&internal::log_silencer_count_mutex_); + MutexLock lock(internal::LogSilencerMutex()); ++internal::log_silencer_count_; }; LogSilencer::~LogSilencer() { - MutexLock lock(&internal::log_silencer_count_mutex_); + MutexLock lock(internal::LogSilencerMutex()); --internal::log_silencer_count_; }; -- cgit v1.2.3