Don't allow singleton use w/o registrationComplete()
authorAndrii Grynenko <andrii@fb.com>
Tue, 4 Apr 2017 03:04:44 +0000 (20:04 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 4 Apr 2017 03:08:12 +0000 (20:08 -0700)
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

folly/Singleton-inl.h
folly/Singleton.cpp
folly/Singleton.h

index cacfec18c64702f4b7558230505b410d11f2759f..2e69d90e2d9a0673bbaac750b6ada2999c7078eb 100644 (file)
@@ -230,6 +230,17 @@ void SingletonHolder<T>::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;
   }
index 67e6fd811cab7bac48635c1d628a53826df45ac4..4f24328e9b2a13f4ab1b03f018933a4afbf386a2 100644 (file)
 
 #include <folly/Singleton.h>
 
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
+
 #include <atomic>
 #include <cstdio>
 #include <cstdlib>
 
 #include <folly/ScopeGuard.h>
 
+#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(
index 2c699e4793d7224c54a45b6acc5dbb9cdeec0962..e8344cef55348bba3375de28b91e4b414f846ffd 100644 (file)
@@ -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();