From a9abc7831e45257d334cfa682746b6cadf9e95d9 Mon Sep 17 00:00:00 2001 From: Adam Cozzette Date: Fri, 6 Jul 2018 14:12:33 -0700 Subject: Fix initialization with Visual Studio It appears that Visual Studio does not work well with std::once_flag because it has a bug causing it to initialize that during dynamic initialization instead of constant initialization. This change works around the problem by using function static initializers instead. @gerben-s originally wrote this change for the Google-internal codebase but I am just cherry-picking it here. This fixes #4773. --- src/google/protobuf/stubs/common.cc | 64 ++++++++++++------------------------- src/google/protobuf/stubs/common.h | 15 ++++++--- 2 files changed, 30 insertions(+), 49 deletions(-) (limited to 'src/google/protobuf/stubs') diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc index 33d24c57..6544c6ed 100755 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -339,66 +339,42 @@ namespace internal { typedef void OnShutdownFunc(); struct ShutdownData { ~ShutdownData() { - for (int i = 0; i < functions.size(); i++) { - functions[i](); - } - for (int i = 0; i < strings.size(); i++) { - strings[i]->~string(); - } - for (int i = 0; i < messages.size(); i++) { - messages[i]->~MessageLite(); - } + std::reverse(functions.begin(), functions.end()); + for (auto pair : functions) pair.first(pair.second); } - std::vector functions; - std::vector strings; - std::vector messages; + static ShutdownData* get() { + static auto* data = new ShutdownData; + return data; + } + + std::vector> functions; Mutex mutex; }; -ShutdownData* shutdown_data = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(shutdown_functions_init); - -void InitShutdownFunctions() { - shutdown_data = new ShutdownData; -} - -inline void InitShutdownFunctionsOnce() { - GoogleOnceInit(&shutdown_functions_init, &InitShutdownFunctions); +static void RunZeroArgFunc(const void* arg) { + reinterpret_cast(const_cast(arg))(); } void OnShutdown(void (*func)()) { - InitShutdownFunctionsOnce(); - MutexLock lock(&shutdown_data->mutex); - shutdown_data->functions.push_back(func); + OnShutdownRun(RunZeroArgFunc, reinterpret_cast(func)); } -void OnShutdownDestroyString(const std::string* ptr) { - InitShutdownFunctionsOnce(); +void OnShutdownRun(void (*f)(const void*), const void* arg) { + auto shutdown_data = ShutdownData::get(); MutexLock lock(&shutdown_data->mutex); - shutdown_data->strings.push_back(ptr); -} - -void OnShutdownDestroyMessage(const void* ptr) { - InitShutdownFunctionsOnce(); - MutexLock lock(&shutdown_data->mutex); - shutdown_data->messages.push_back(static_cast(ptr)); + shutdown_data->functions.push_back(std::make_pair(f, arg)); } } // namespace internal void ShutdownProtobufLibrary() { - internal::InitShutdownFunctionsOnce(); - - // We don't need to lock shutdown_functions_mutex because it's up to the - // caller to make sure that no one is using the library before this is - // called. - - // Make it safe to call this multiple times. - if (internal::shutdown_data == NULL) return; - - delete internal::shutdown_data; - internal::shutdown_data = NULL; + // This function should be called only once, but accepts multiple calls. + static bool is_shutdown = false; + if (!is_shutdown) { + delete internal::ShutdownData::get(); + is_shutdown = true; + } } #if PROTOBUF_USE_EXCEPTIONS diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 5d320764..f505f46a 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -193,17 +193,22 @@ LIBPROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid( // // It is safe to call this multiple times. However, it is not safe to use // any other part of the protocol buffers library after -// ShutdownProtobufLibrary() has been called. +// ShutdownProtobufLibrary() has been called. Furthermore this call is not +// thread safe, user needs to synchronize multiple calls. LIBPROTOBUF_EXPORT void ShutdownProtobufLibrary(); namespace internal { // Register a function to be called when ShutdownProtocolBuffers() is called. LIBPROTOBUF_EXPORT void OnShutdown(void (*func)()); -// Destroy the string (call string destructor) -LIBPROTOBUF_EXPORT void OnShutdownDestroyString(const std::string* ptr); -// Destroy (not delete) the message -LIBPROTOBUF_EXPORT void OnShutdownDestroyMessage(const void* ptr); +// Run an arbitrary function on an arg +LIBPROTOBUF_EXPORT void OnShutdownRun(void (*f)(const void*), const void* arg); + +template +T* OnShutdownDelete(T* p) { + OnShutdownRun([](const void* p) { delete static_cast(p); }, p); + return p; +} } // namespace internal -- cgit v1.2.3