Commit 6b1fb6fa authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Extract getSingletonStackTrace

Summary:
[Folly] Extract `getSingletonStackTrace` to its own detail library.

For now, just do conditional definition, avoiding the atomic and the global constructor.

Reviewed By: andriigrynenko

Differential Revision: D13213446

fbshipit-source-id: 95af5701d1c29e0ef24ba48e9bcec9ec565b31b4
parent da7f6959
...@@ -30,10 +30,7 @@ ...@@ -30,10 +30,7 @@
#include <folly/Demangle.h> #include <folly/Demangle.h>
#include <folly/Format.h> #include <folly/Format.h>
#include <folly/ScopeGuard.h> #include <folly/ScopeGuard.h>
#include <folly/detail/SingletonStackTrace.h>
#if FOLLY_USE_SYMBOLIZER
#include <folly/experimental/symbolizer/Symbolizer.h> // @manual
#endif
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__)
#define FOLLY_SINGLETON_HAVE_DLSYM 1 #define FOLLY_SINGLETON_HAVE_DLSYM 1
...@@ -98,12 +95,10 @@ std::string TypeDescriptor::name() const { ...@@ -98,12 +95,10 @@ std::string TypeDescriptor::name() const {
[[noreturn]] void singletonWarnLeakyInstantiatingNotRegisteredAndAbort( [[noreturn]] void singletonWarnLeakyInstantiatingNotRegisteredAndAbort(
const TypeDescriptor& type) { const TypeDescriptor& type) {
auto ptr = SingletonVault::stackTraceGetter().load(); auto trace = detail::getSingletonStackTrace();
LOG(FATAL) << "Creating instance for unregistered singleton: " << type.name() LOG(FATAL) << "Creating instance for unregistered singleton: " << type.name()
<< "\n" << "\n"
<< "Stacktrace:" << "Stacktrace:\n" << (trace != "" ? trace : "(not available)");
<< "\n"
<< (ptr ? (*ptr)() : "(not available)");
} }
[[noreturn]] void singletonWarnRegisterMockEarlyAndAbort( [[noreturn]] void singletonWarnRegisterMockEarlyAndAbort(
...@@ -132,43 +127,27 @@ void singletonWarnDestroyInstanceLeak( ...@@ -132,43 +127,27 @@ void singletonWarnDestroyInstanceLeak(
[[noreturn]] void singletonWarnCreateUnregisteredAndAbort( [[noreturn]] void singletonWarnCreateUnregisteredAndAbort(
const TypeDescriptor& type) { const TypeDescriptor& type) {
auto ptr = SingletonVault::stackTraceGetter().load(); auto trace = detail::getSingletonStackTrace();
LOG(FATAL) << "Creating instance for unregistered singleton: " << type.name() LOG(FATAL) << "Creating instance for unregistered singleton: " << type.name()
<< "\n" << "\n"
<< "Stacktrace:" << "Stacktrace:\n" << (trace != "" ? trace : "(not available)");
<< "\n"
<< (ptr ? (*ptr)() : "(not available)");
} }
[[noreturn]] void singletonWarnCreateBeforeRegistrationCompleteAndAbort( [[noreturn]] void singletonWarnCreateBeforeRegistrationCompleteAndAbort(
const TypeDescriptor& type) { const TypeDescriptor& type) {
auto stack_trace_getter = SingletonVault::stackTraceGetter().load(); auto trace = detail::getSingletonStackTrace();
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 " LOG(FATAL) << "Singleton " << type.name() << " requested before "
<< "registrationComplete() call.\n" << "registrationComplete() call.\n"
<< "This usually means that either main() never called " << "This usually means that either main() never called "
<< "folly::init, or singleton was requested before main() " << "folly::init, or singleton was requested before main() "
<< "(which is not allowed).\n" << "(which is not allowed).\n"
<< stack_trace; << "Stacktrace:\n" << (trace != "" ? trace : "(not available)");
} }
void singletonPrintDestructionStackTrace(const TypeDescriptor& type) { void singletonPrintDestructionStackTrace(const TypeDescriptor& type) {
std::string output = "Singleton " + type.name() + " was released.\n"; auto trace = detail::getSingletonStackTrace();
LOG(ERROR) << "Singleton " << type.name() << " was released.\n"
auto stack_trace_getter = SingletonVault::stackTraceGetter().load(); << "Stacktrace:\n" << (trace != "" ? trace : "(not available)");
auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
if (stack_trace.empty()) {
output += "Failed to get release stack trace.";
} else {
output += "Release stack trace:\n";
output += stack_trace;
}
LOG(ERROR) << output;
} }
[[noreturn]] void singletonThrowNullCreator(const std::type_info& type) { [[noreturn]] void singletonThrowNullCreator(const std::type_info& type) {
...@@ -384,46 +363,4 @@ void SingletonVault::scheduleDestroyInstances() { ...@@ -384,46 +363,4 @@ void SingletonVault::scheduleDestroyInstances() {
std::atexit([] { SingletonVault::singleton()->destroyInstances(); }); std::atexit([] { SingletonVault::singleton()->destroyInstances(); });
} }
// If we're using folly's Symbolizer, create a static initializer to setup
// Singltone's to use it to print stack traces. It's important that we keep
// this in the same compilation unit as the `SingletonVault` so that it's
// setup/used iff singleton's are used.
#if FOLLY_USE_SYMBOLIZER
namespace {
std::string stackTraceGetter() {
// Get and symbolize stack trace
constexpr size_t kMaxStackTraceDepth = 100;
symbolizer::FrameArray<kMaxStackTraceDepth> addresses;
if (!getStackTraceSafe(addresses)) {
return "";
} else {
constexpr size_t kDefaultCapacity = 500;
symbolizer::ElfCache elfCache(kDefaultCapacity);
symbolizer::Symbolizer symbolizer(&elfCache);
symbolizer.symbolize(addresses);
symbolizer::StringSymbolizePrinter printer;
printer.println(addresses);
return printer.str();
}
}
struct SetStackTraceGetter {
SetStackTraceGetter() {
SingletonVault::stackTraceGetter().store(stackTraceGetter);
}
};
#ifdef __APPLE__
// OS X doesn't support constructor priorities.
SetStackTraceGetter setStackTraceGetter;
#else
SetStackTraceGetter __attribute__((__init_priority__(101))) setStackTraceGetter;
#endif
} // namespace
#endif
} // namespace folly } // namespace folly
...@@ -503,13 +503,6 @@ class SingletonVault { ...@@ -503,13 +503,6 @@ class SingletonVault {
return &detail::createGlobal<SingletonVault, VaultTag>(); return &detail::createGlobal<SingletonVault, VaultTag>();
} }
typedef std::string (*StackTraceGetterPtr)();
static std::atomic<StackTraceGetterPtr>& stackTraceGetter() {
struct Result : std::atomic<StackTraceGetterPtr> {};
return detail::createGlobal<Result, void>();
}
void setType(Type type) { void setType(Type type) {
type_ = type; type_ = type;
} }
......
/*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/detail/SingletonStackTrace.h>
#include <folly/portability/Config.h>
#if FOLLY_USE_SYMBOLIZER
#include <folly/experimental/symbolizer/Symbolizer.h> // @manual
#endif
namespace folly {
namespace detail {
std::string getSingletonStackTrace() {
#if FOLLY_USE_SYMBOLIZER
// Get and symbolize stack trace
constexpr size_t kMaxStackTraceDepth = 100;
symbolizer::FrameArray<kMaxStackTraceDepth> addresses;
if (!getStackTraceSafe(addresses)) {
return "";
} else {
constexpr size_t kDefaultCapacity = 500;
symbolizer::ElfCache elfCache(kDefaultCapacity);
symbolizer::Symbolizer symbolizer(&elfCache);
symbolizer.symbolize(addresses);
symbolizer::StringSymbolizePrinter printer;
printer.println(addresses);
return printer.str();
}
#else
return "";
#endif
}
} // namespace detail
} // namespace folly
/*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
#include <folly/CPortability.h>
namespace folly {
namespace detail {
// empty-string indicates stack-trace functionality is not available
std::string getSingletonStackTrace();
} // namespace detail
} // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment