Don't allow singleton use w/o registrationComplete()
authorAndrii Grynenko <andrii@fb.com>
Tue, 21 Mar 2017 16:45:01 +0000 (09:45 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 21 Mar 2017 16:50:32 +0000 (09:50 -0700)
Summary: Submitting mostly to see what breaks.

Reviewed By: yfeldblum

Differential Revision: D4249032

fbshipit-source-id: d4e3fdfd57750c8dcabdb4c01ab3b528c4818624

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

index 2656084e81bae8abedb032d2b54ddacd815c388e..207a0f7dc32536b3cdf2ff11107b2598b55d2ccf 100644 (file)
@@ -224,6 +224,17 @@ void SingletonHolder<T>::createInstance() {
   creating_thread_.store(std::this_thread::get_id(), std::memory_order_release);
 
   auto state = vault_.state_.rlock();
   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(FATAL) << "Singleton " << type().name() << " requested before "
+               << "registrationComplete() call. " << stack_trace;
+  }
   if (state->state == SingletonVault::SingletonVaultState::Quiescing) {
     return;
   }
   if (state->state == SingletonVault::SingletonVaultState::Quiescing) {
     return;
   }
index 67e6fd811cab7bac48635c1d628a53826df45ac4..4f24328e9b2a13f4ab1b03f018933a4afbf386a2 100644 (file)
 
 #include <folly/Singleton.h>
 
 
 #include <folly/Singleton.h>
 
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
+
 #include <atomic>
 #include <cstdio>
 #include <cstdlib>
 #include <atomic>
 #include <cstdio>
 #include <cstdlib>
 
 #include <folly/ScopeGuard.h>
 
 
 #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 {
 
 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(
 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();
 
   // Destructor is only called by unit tests to check destroyInstances.
   ~SingletonVault();