From: Andrii Grynenko Date: Tue, 4 Apr 2017 03:04:44 +0000 (-0700) Subject: Don't allow singleton use w/o registrationComplete() X-Git-Tag: v2017.04.10.00~21 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=7d0d018f7661e1994c7f68c8b80483d80a96f9fd;hp=0fdbb3df4230829df93437f2143384c6aa27befb;p=folly.git Don't allow singleton use w/o registrationComplete() Summary: This is same as D4249032, but for now this is only enabled in dbg and dev builds. I'm planning to bump this to FATAL later, once we fix know problematic main()s. Reviewed By: lbrandy, yfeldblum Differential Revision: D4821763 fbshipit-source-id: 5f7930f8cbcb10275d23a89848f1ec8ee34a8020 --- diff --git a/folly/Singleton-inl.h b/folly/Singleton-inl.h index cacfec18..2e69d90e 100644 --- a/folly/Singleton-inl.h +++ b/folly/Singleton-inl.h @@ -230,6 +230,17 @@ void SingletonHolder::createInstance() { creating_thread_.store(std::this_thread::get_id(), std::memory_order_release); auto state = vault_.state_.rlock(); + if (vault_.type_ != SingletonVault::Type::Relaxed && + !state->registrationComplete) { + auto stack_trace_getter = SingletonVault::stackTraceGetter().load(); + auto stack_trace = stack_trace_getter ? stack_trace_getter() : ""; + if (!stack_trace.empty()) { + stack_trace = "Stack trace:\n" + stack_trace; + } + + LOG(DFATAL) << "Singleton " << type().name() << " requested before " + << "registrationComplete() call. " << stack_trace; + } if (state->state == SingletonVault::SingletonVaultState::Quiescing) { return; } diff --git a/folly/Singleton.cpp b/folly/Singleton.cpp index 67e6fd81..4f24328e 100644 --- a/folly/Singleton.cpp +++ b/folly/Singleton.cpp @@ -16,6 +16,10 @@ #include +#ifndef _WIN32 +#include +#endif + #include #include #include @@ -24,8 +28,26 @@ #include +#if !defined(_WIN32) && !defined(__APPLE__) +static void hs_init_weak(int* argc, char** argv[]) + __attribute__((__weakref__("hs_init"))); +#endif + namespace folly { +SingletonVault::Type SingletonVault::defaultVaultType() { +#if !defined(_WIN32) && !defined(__APPLE__) + bool isPython = dlsym(RTLD_DEFAULT, "Py_Main"); + bool isHaskel = &::hs_init_weak || dlsym(RTLD_DEFAULT, "hs_init"); + bool isJVM = dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs"); + bool isD = dlsym(RTLD_DEFAULT, "_d_run_main"); + + return isPython || isHaskel || isJVM || isD ? Type::Relaxed : Type::Strict; +#else + return Type::Relaxed; +#endif +} + namespace detail { [[noreturn]] void singletonWarnDoubleRegistrationAndAbort( diff --git a/folly/Singleton.h b/folly/Singleton.h index 2c699e47..e8344cef 100644 --- a/folly/Singleton.h +++ b/folly/Singleton.h @@ -358,7 +358,9 @@ class SingletonVault { } }; - explicit SingletonVault(Type type = Type::Strict) : type_(type) {} + static Type defaultVaultType(); + + explicit SingletonVault(Type type = defaultVaultType()) : type_(type) {} // Destructor is only called by unit tests to check destroyInstances. ~SingletonVault();