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 cacfec1..2e69d90 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 67e6fd8..4f24328 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 2c699e4..e8344ce 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();