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/descriptor.cc | 97 ++++++---------------- src/google/protobuf/extension_set.cc | 92 ++++---------------- src/google/protobuf/extension_set.h | 56 ++++--------- .../protobuf/generated_message_reflection.cc | 26 +++--- src/google/protobuf/generated_message_util.cc | 27 +++--- src/google/protobuf/generated_message_util.h | 20 ++++- src/google/protobuf/message.cc | 23 +---- src/google/protobuf/message_lite.h | 8 -- src/google/protobuf/stubs/common.cc | 64 +++++--------- src/google/protobuf/stubs/common.h | 15 ++-- src/google/protobuf/unknown_field_set.cc | 23 +---- 11 files changed, 132 insertions(+), 319 deletions(-) diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 83eae519..fc3a9c77 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -479,15 +479,8 @@ typedef std::map ExtensionsGroupedByDescriptorMap; typedef HASH_MAP LocationsByPathMap; -std::set* allowed_proto3_extendees_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_); - -void DeleteAllowedProto3Extendee() { - delete allowed_proto3_extendees_; -} - -void InitAllowedProto3Extendee() { - allowed_proto3_extendees_ = new std::set; +std::set* NewAllowedProto3Extendee() { + auto allowed_proto3_extendees = new std::set; const char* kOptionNames[] = { "FileOptions", "MessageOptions", "FieldOptions", "EnumOptions", "EnumValueOptions", "ServiceOptions", "MethodOptions", "OneofOptions"}; @@ -495,14 +488,13 @@ void InitAllowedProto3Extendee() { // descriptor.proto has a different package name in opensource. We allow // both so the opensource protocol compiler can also compile internal // proto3 files with custom options. See: b/27567912 - allowed_proto3_extendees_->insert(string("google.protobuf.") + + allowed_proto3_extendees->insert(string("google.protobuf.") + kOptionNames[i]); // Split the word to trick the opensource processing scripts so they // will keep the origial package name. - allowed_proto3_extendees_->insert(string("proto") + "2." + kOptionNames[i]); + allowed_proto3_extendees->insert(string("proto") + "2." + kOptionNames[i]); } - - google::protobuf::internal::OnShutdown(&DeleteAllowedProto3Extendee); + return allowed_proto3_extendees; } // Checks whether the extendee type is allowed in proto3. @@ -510,9 +502,10 @@ void InitAllowedProto3Extendee() { // instead of comparing the descriptor directly because the extensions may be // defined in a different pool. bool AllowedExtendeeInProto3(const string& name) { - ::google::protobuf::GoogleOnceInit(&allowed_proto3_extendees_init_, &InitAllowedProto3Extendee); - return allowed_proto3_extendees_->find(name) != - allowed_proto3_extendees_->end(); + static auto allowed_proto3_extendees = + internal::OnShutdownDelete(NewAllowedProto3Extendee()); + return allowed_proto3_extendees->find(name) != + allowed_proto3_extendees->end(); } } // anonymous namespace @@ -829,31 +822,10 @@ FileDescriptorTables::FileDescriptorTables() FileDescriptorTables::~FileDescriptorTables() {} -namespace { - -FileDescriptorTables* file_descriptor_tables_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(file_descriptor_tables_once_init_); - -void DeleteFileDescriptorTables() { - delete file_descriptor_tables_; - file_descriptor_tables_ = NULL; -} - -void InitFileDescriptorTables() { - file_descriptor_tables_ = new FileDescriptorTables(); - internal::OnShutdown(&DeleteFileDescriptorTables); -} - -inline void InitFileDescriptorTablesOnce() { - ::google::protobuf::GoogleOnceInit( - &file_descriptor_tables_once_init_, &InitFileDescriptorTables); -} - -} // anonymous namespace - inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() { - InitFileDescriptorTablesOnce(); - return *file_descriptor_tables_; + static auto file_descriptor_tables = + internal::OnShutdownDelete(new FileDescriptorTables()); + return *file_descriptor_tables; } void DescriptorPool::Tables::AddCheckpoint() { @@ -1335,42 +1307,28 @@ bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { namespace { - -EncodedDescriptorDatabase* generated_database_ = NULL; -DescriptorPool* generated_pool_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_); - -void DeleteGeneratedPool() { - delete generated_database_; - generated_database_ = NULL; - delete generated_pool_; - generated_pool_ = NULL; -} - -static void InitGeneratedPool() { - generated_database_ = new EncodedDescriptorDatabase; - generated_pool_ = new DescriptorPool(generated_database_); - generated_pool_->InternalSetLazilyBuildDependencies(); - - internal::OnShutdown(&DeleteGeneratedPool); +EncodedDescriptorDatabase* GeneratedDatabase() { + static auto generated_database = + internal::OnShutdownDelete(new EncodedDescriptorDatabase()); + return generated_database; } -inline void InitGeneratedPoolOnce() { - ::google::protobuf::GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool); +DescriptorPool* NewGeneratedPool() { + auto generated_pool = new DescriptorPool(GeneratedDatabase()); + generated_pool->InternalSetLazilyBuildDependencies(); + return generated_pool; } } // anonymous namespace -const DescriptorPool* DescriptorPool::generated_pool() { - InitGeneratedPoolOnce(); - return generated_pool_; +DescriptorPool* DescriptorPool::internal_generated_pool() { + static DescriptorPool* generated_pool = + internal::OnShutdownDelete(NewGeneratedPool()); + return generated_pool; } - - -DescriptorPool* DescriptorPool::internal_generated_pool() { - InitGeneratedPoolOnce(); - return generated_pool_; +const DescriptorPool* DescriptorPool::generated_pool() { + return internal_generated_pool(); } void DescriptorPool::InternalAddGeneratedFile( @@ -1397,8 +1355,7 @@ void DescriptorPool::InternalAddGeneratedFile( // Therefore, when we parse one, we have to be very careful to avoid using // any descriptor-based operations, since this might cause infinite recursion // or deadlock. - InitGeneratedPoolOnce(); - GOOGLE_CHECK(generated_database_->Add(encoded_file_descriptor, size)); + GOOGLE_CHECK(GeneratedDatabase()->Add(encoded_file_descriptor, size)); } diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index b587b38f..cb205c4f 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -80,27 +79,17 @@ inline bool is_packable(WireFormatLite::WireType type) { // Registry stuff. typedef hash_map, ExtensionInfo> ExtensionRegistry; -ExtensionRegistry* registry_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(registry_init_); -void DeleteRegistry() { - delete registry_; - registry_ = NULL; -} - -void InitRegistry() { - registry_ = new ExtensionRegistry; - OnShutdown(&DeleteRegistry); -} +static const ExtensionRegistry* global_registry = nullptr; // This function is only called at startup, so there is no need for thread- // safety. void Register(const MessageLite* containing_type, int number, ExtensionInfo info) { - ::google::protobuf::GoogleOnceInit(®istry_init_, &InitRegistry); - - if (!InsertIfNotPresent(registry_, std::make_pair(containing_type, number), - info)) { + static auto local_static_registry = OnShutdownDelete(new ExtensionRegistry); + global_registry = local_static_registry; + if (!InsertIfNotPresent(local_static_registry, + std::make_pair(containing_type, number), info)) { GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \"" << containing_type->GetTypeName() << "\", field number " << number << "."; @@ -109,9 +98,9 @@ void Register(const MessageLite* containing_type, const ExtensionInfo* FindRegisteredExtension( const MessageLite* containing_type, int number) { - return (registry_ == NULL) - ? NULL - : FindOrNull(*registry_, std::make_pair(containing_type, number)); + return global_registry == nullptr + ? nullptr + : FindOrNull(*global_registry, std::make_pair(containing_type, number)); } } // namespace @@ -1911,67 +1900,16 @@ void ExtensionSet::Erase(int key) { // ================================================================== // Default repeated field instances for iterator-compatible accessors -GOOGLE_PROTOBUF_DECLARE_ONCE(repeated_primitive_generic_type_traits_once_init_); -GOOGLE_PROTOBUF_DECLARE_ONCE(repeated_string_type_traits_once_init_); -GOOGLE_PROTOBUF_DECLARE_ONCE(repeated_message_generic_type_traits_once_init_); - -void RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields() { - default_repeated_field_int32_ = new RepeatedField; - default_repeated_field_int64_ = new RepeatedField; - default_repeated_field_uint32_ = new RepeatedField; - default_repeated_field_uint64_ = new RepeatedField; - default_repeated_field_double_ = new RepeatedField; - default_repeated_field_float_ = new RepeatedField; - default_repeated_field_bool_ = new RepeatedField; - OnShutdown(&DestroyDefaultRepeatedFields); -} - -void RepeatedPrimitiveGenericTypeTraits::DestroyDefaultRepeatedFields() { - delete default_repeated_field_int32_; - delete default_repeated_field_int64_; - delete default_repeated_field_uint32_; - delete default_repeated_field_uint64_; - delete default_repeated_field_double_; - delete default_repeated_field_float_; - delete default_repeated_field_bool_; -} - -void RepeatedStringTypeTraits::InitializeDefaultRepeatedFields() { - default_repeated_field_ = new RepeatedFieldType; - OnShutdown(&DestroyDefaultRepeatedFields); -} - -void RepeatedStringTypeTraits::DestroyDefaultRepeatedFields() { - delete default_repeated_field_; -} - -void RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields() { - default_repeated_field_ = new RepeatedFieldType; - OnShutdown(&DestroyDefaultRepeatedFields); -} - -void RepeatedMessageGenericTypeTraits::DestroyDefaultRepeatedFields() { - delete default_repeated_field_; +const RepeatedPrimitiveDefaults* RepeatedPrimitiveDefaults::default_instance() { + static auto instance = OnShutdownDelete(new RepeatedPrimitiveDefaults); + return instance; } -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_ = NULL; -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_ = NULL; -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_ = NULL; -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_ = NULL; -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_ = NULL; -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_ = NULL; -const RepeatedField* -RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_ = NULL; const RepeatedStringTypeTraits::RepeatedFieldType* -RepeatedStringTypeTraits::default_repeated_field_ = NULL; -const RepeatedMessageGenericTypeTraits::RepeatedFieldType* -RepeatedMessageGenericTypeTraits::default_repeated_field_ = NULL; +RepeatedStringTypeTraits::GetDefaultRepeatedField() { + static auto instance = OnShutdownDelete(new RepeatedFieldType); + return instance; +} } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index c4796629..a1535baa 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -880,18 +880,17 @@ class RepeatedPrimitiveTypeTraits { LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_; -class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits { +class LIBPROTOBUF_EXPORT RepeatedPrimitiveDefaults { private: template friend class RepeatedPrimitiveTypeTraits; - static void InitializeDefaultRepeatedFields(); - static void DestroyDefaultRepeatedFields(); - static const RepeatedField* default_repeated_field_int32_; - static const RepeatedField* default_repeated_field_int64_; - static const RepeatedField* default_repeated_field_uint32_; - static const RepeatedField* default_repeated_field_uint64_; - static const RepeatedField* default_repeated_field_double_; - static const RepeatedField* default_repeated_field_float_; - static const RepeatedField* default_repeated_field_bool_; + static const RepeatedPrimitiveDefaults* default_instance(); + RepeatedField default_repeated_field_int32_; + RepeatedField default_repeated_field_int64_; + RepeatedField default_repeated_field_uint32_; + RepeatedField default_repeated_field_uint64_; + RepeatedField default_repeated_field_double_; + RepeatedField default_repeated_field_float_; + RepeatedField default_repeated_field_bool_; }; #define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \ @@ -919,11 +918,8 @@ template<> inline void RepeatedPrimitiveTypeTraits::Add( \ } \ template<> inline const RepeatedField* \ RepeatedPrimitiveTypeTraits::GetDefaultRepeatedField() { \ - ::google::protobuf::GoogleOnceInit( \ - &repeated_primitive_generic_type_traits_once_init_, \ - &RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields); \ - return RepeatedPrimitiveGenericTypeTraits:: \ - default_repeated_field_##TYPE##_; \ + return &RepeatedPrimitiveDefaults::default_instance() \ + ->default_repeated_field_##TYPE##_; \ } \ template<> inline const RepeatedField& \ RepeatedPrimitiveTypeTraits::GetRepeated(int number, \ @@ -980,8 +976,6 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { } }; -LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_string_type_traits_once_init_; - class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { public: typedef const string& ConstType; @@ -1024,11 +1018,7 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { is_packed, NULL)); } - static const RepeatedFieldType* GetDefaultRepeatedField() { - ::google::protobuf::GoogleOnceInit(&repeated_string_type_traits_once_init_, - &InitializeDefaultRepeatedFields); - return default_repeated_field_; - } + static const RepeatedFieldType* GetDefaultRepeatedField(); template static void Register(int number, FieldType type, bool is_packed) { @@ -1039,7 +1029,6 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { private: static void InitializeDefaultRepeatedFields(); static void DestroyDefaultRepeatedFields(); - static const RepeatedFieldType *default_repeated_field_; }; // ------------------------------------------------------------------- @@ -1230,28 +1219,11 @@ class RepeatedMessageTypeTraits { } }; -LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_message_generic_type_traits_once_init_; - -// This class exists only to hold a generic default empty repeated field for all -// message-type repeated field extensions. -class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits { - public: - typedef RepeatedPtrField<::google::protobuf::MessageLite*> RepeatedFieldType; - private: - template friend class RepeatedMessageTypeTraits; - static void InitializeDefaultRepeatedFields(); - static void DestroyDefaultRepeatedFields(); - static const RepeatedFieldType* default_repeated_field_; -}; - template inline const typename RepeatedMessageTypeTraits::RepeatedFieldType* RepeatedMessageTypeTraits::GetDefaultRepeatedField() { - ::google::protobuf::GoogleOnceInit( - &repeated_message_generic_type_traits_once_init_, - &RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields); - return reinterpret_cast( - RepeatedMessageGenericTypeTraits::default_repeated_field_); + static auto instance = OnShutdownDelete(new RepeatedFieldType); + return instance; } // ------------------------------------------------------------------- diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 247f772c..74ad00e7 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -2327,32 +2327,26 @@ class AssignDescriptorsHelper { // automatically delete the allocated reflection. MetadataOwner owns // all the allocated reflection instances. struct MetadataOwner { + ~MetadataOwner() { + for (auto range : metadata_arrays_) { + for (const Metadata* m = range.first; m < range.second; m++) { + delete m->reflection; + } + } + } + void AddArray(const Metadata* begin, const Metadata* end) { MutexLock lock(&mu_); metadata_arrays_.push_back(std::make_pair(begin, end)); } static MetadataOwner* Instance() { - static MetadataOwner* res = new MetadataOwner; + static MetadataOwner* res = OnShutdownDelete(new MetadataOwner); return res; } private: - // Use the constructor to register the shutdown code. Because c++ makes sure - // this called only once. - MetadataOwner() { OnShutdown(&DeleteMetadata); } - ~MetadataOwner() { - for (int i = 0; i < metadata_arrays_.size(); i++) { - for (const Metadata* m = metadata_arrays_[i].first; - m < metadata_arrays_[i].second; m++) { - delete m->reflection; - } - } - } - - static void DeleteMetadata() { - delete Instance(); - } + MetadataOwner() = default; // private because singleton Mutex mu_; std::vector > metadata_arrays_; diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index dac8ca90..e0241361 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -57,6 +57,12 @@ namespace google { namespace protobuf { namespace internal { +void DestroyMessage(const void* message) { + static_cast(message)->~MessageLite(); +} +void DestroyString(const void* s) { static_cast(s)->~string(); } + +ExplicitlyConstructed fixed_address_empty_string; double Infinity() { return std::numeric_limits::infinity(); @@ -65,14 +71,15 @@ double NaN() { return std::numeric_limits::quiet_NaN(); } -ExplicitlyConstructed<::std::string> fixed_address_empty_string; -GOOGLE_PROTOBUF_DECLARE_ONCE(empty_string_once_init_); - -void DeleteEmptyString() { fixed_address_empty_string.Destruct(); } - -void InitEmptyString() { +static bool InitProtobufDefaultsImpl() { fixed_address_empty_string.DefaultConstruct(); - OnShutdown(&DeleteEmptyString); + OnShutdownDestroyString(fixed_address_empty_string.get_mutable()); + return true; +} + +void InitProtobufDefaults() { + static bool is_inited = InitProtobufDefaultsImpl(); + (void)is_inited; } size_t StringSpaceUsedExcludingSelfLong(const string& str) { @@ -86,12 +93,6 @@ size_t StringSpaceUsedExcludingSelfLong(const string& str) { } } - - -void InitProtobufDefaults() { - GetEmptyString(); -} - template const T& Get(const void* ptr) { return *static_cast(ptr); diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 706df383..04f68a6e 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -109,6 +109,13 @@ namespace internal { LIBPROTOBUF_EXPORT double Infinity(); LIBPROTOBUF_EXPORT double NaN(); +LIBPROTOBUF_EXPORT void InitProtobufDefaults(); + +// This used by proto1 +inline const std::string& GetEmptyString() { + InitProtobufDefaults(); + return GetEmptyStringAlreadyInited(); +} // True if IsInitialized() is true for all elements of t. Type is expected // to be a RepeatedPtrField. It's useful to have this @@ -137,8 +144,6 @@ bool AllAreInitializedWeak(const ::google::protobuf::RepeatedPtrField& t) { return true; } -LIBPROTOBUF_EXPORT void InitProtobufDefaults(); - struct LIBPROTOBUF_EXPORT FieldMetadata { uint32 offset; // offset of this field in the struct uint32 tag; // field * 8 + wire_type @@ -368,6 +373,17 @@ inline void InitSCC(SCCInfoBase* scc) { if (GOOGLE_PREDICT_FALSE(status != SCCInfoBase::kInitialized)) InitSCCImpl(scc); } +LIBPROTOBUF_EXPORT void DestroyMessage(const void* message); +LIBPROTOBUF_EXPORT void DestroyString(const void* s); +// Destroy (not delete) the message +inline void OnShutdownDestroyMessage(const void* ptr) { + OnShutdownRun(DestroyMessage, ptr); +} +// Destroy the string (call string destructor) +inline void OnShutdownDestroyString(const std::string* ptr) { + OnShutdownRun(DestroyString, ptr); +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 810db233..9b758080 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -262,9 +262,6 @@ namespace { class GeneratedMessageFactory : public MessageFactory { public: - GeneratedMessageFactory(); - ~GeneratedMessageFactory(); - static GeneratedMessageFactory* singleton(); typedef void RegistrationFunc(const string&); @@ -284,25 +281,9 @@ class GeneratedMessageFactory : public MessageFactory { hash_map type_map_; }; -GeneratedMessageFactory* generated_message_factory_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_); - -void ShutdownGeneratedMessageFactory() { - delete generated_message_factory_; -} - -void InitGeneratedMessageFactory() { - generated_message_factory_ = new GeneratedMessageFactory; - internal::OnShutdown(&ShutdownGeneratedMessageFactory); -} - -GeneratedMessageFactory::GeneratedMessageFactory() {} -GeneratedMessageFactory::~GeneratedMessageFactory() {} - GeneratedMessageFactory* GeneratedMessageFactory::singleton() { - ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, - &InitGeneratedMessageFactory); - return generated_message_factory_; + static auto instance = internal::OnShutdownDelete(new GeneratedMessageFactory); + return instance; } void GeneratedMessageFactory::RegisterFile( diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index 4cbec330..b8644142 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -129,19 +129,11 @@ class ExplicitlyConstructed { // Default empty string object. Don't use this directly. Instead, call // GetEmptyString() to get the reference. LIBPROTOBUF_EXPORT extern ExplicitlyConstructed<::std::string> fixed_address_empty_string; -LIBPROTOBUF_EXPORT extern ProtobufOnceType empty_string_once_init_; -LIBPROTOBUF_EXPORT void InitEmptyString(); - LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyStringAlreadyInited() { return fixed_address_empty_string.get(); } -LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyString() { - ::google::protobuf::GoogleOnceInit(&empty_string_once_init_, &InitEmptyString); - return GetEmptyStringAlreadyInited(); -} - LIBPROTOBUF_EXPORT size_t StringSpaceUsedExcludingSelfLong(const string& str); #endif // SWIG } // namespace internal 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 diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 0ada85e5..35f24e7a 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -46,28 +46,9 @@ namespace google { namespace protobuf { -namespace { -// This global instance is returned by unknown_fields() on any message class -// when the object has no unknown fields. This is necessary because we now -// instantiate the UnknownFieldSet dynamically only when required. -UnknownFieldSet* default_unknown_field_set_instance_ = NULL; - -void DeleteDefaultUnknownFieldSet() { - delete default_unknown_field_set_instance_; -} - -void InitDefaultUnknownFieldSet() { - default_unknown_field_set_instance_ = new UnknownFieldSet(); - internal::OnShutdown(&DeleteDefaultUnknownFieldSet); -} - -GOOGLE_PROTOBUF_DECLARE_ONCE(default_unknown_field_set_once_init_); -} - const UnknownFieldSet* UnknownFieldSet::default_instance() { - ::google::protobuf::GoogleOnceInit(&default_unknown_field_set_once_init_, - &InitDefaultUnknownFieldSet); - return default_unknown_field_set_instance_; + static auto instance = internal::OnShutdownDelete(new UnknownFieldSet()); + return instance; } void UnknownFieldSet::ClearFallback() { -- cgit v1.2.3