Merge #15266: memory: Construct globals on first use

77777c5624 log: Construct global logger on first use (MarcoFalke)

Pull request description:

  The (de)initialization order is not well defined in C++, so generally it is not safe to use globals as the (de/con)structor of one global could use the (de/con)structor of another global before/after it has been (con/de)structed.

  Specifically this fixes:
  * `g_logger` might not be initialized on the first use, so do that. (Fixes #15111)

Tree-SHA512: eb9c22f4baf31ebc5b0b9ee6a51d1354bae1f0df186cc0ce818b4483c7b5a7f90268d2b549ee96b4c57f8ef36ab239dc6497f74f3e2ef166038f7437c368297d
This commit is contained in:
MarcoFalke 2019-02-04 14:26:02 -05:00 committed by Vijay Das Manikpuri
parent a894cb607c
commit 15f14806a8
No known key found for this signature in database
GPG Key ID: DB1D81B01DB7C46E
8 changed files with 41 additions and 35 deletions

View File

@ -20,6 +20,6 @@ void CBatchedLogger::Flush()
if (!accept || msg.empty()) { if (!accept || msg.empty()) {
return; return;
} }
g_logger->LogPrintStr(strprintf("%s:\n%s", header, msg)); LogInstance().LogPrintStr(strprintf("%s:\n%s", header, msg));
msg.clear(); msg.clear();
} }

View File

@ -373,8 +373,8 @@ bool InitHTTPServer()
// Update libevent's log handling. Returns false if our version of // Update libevent's log handling. Returns false if our version of
// libevent doesn't support debug logging, in which case we should // libevent doesn't support debug logging, in which case we should
// clear the BCLog::LIBEVENT flag. // clear the BCLog::LIBEVENT flag.
if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
g_logger->DisableCategory(BCLog::LIBEVENT); LogInstance().DisableCategory(BCLog::LIBEVENT);
} }
#ifdef WIN32 #ifdef WIN32

View File

@ -416,7 +416,7 @@ static void HandleSIGTERM(int)
static void HandleSIGHUP(int) static void HandleSIGHUP(int)
{ {
g_logger->m_reopen_file = true; LogInstance().m_reopen_file = true;
} }
#else #else
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
@ -1185,12 +1185,12 @@ static std::string ResolveErrMsg(const char * const optname, const std::string&
*/ */
void InitLogging() void InitLogging()
{ {
g_logger->m_print_to_file = !gArgs.IsArgNegated("-debuglogfile"); LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
g_logger->m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
g_logger->m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
g_logger->m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
g_logger->m_log_threadnames = gArgs.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES); LogInstance().m_log_threadnames = gArgs.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES);
fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
@ -1366,7 +1366,7 @@ bool AppInitParameterInteraction()
if (std::none_of(categories.begin(), categories.end(), if (std::none_of(categories.begin(), categories.end(),
[](std::string cat){return cat == "0" || cat == "none";})) { [](std::string cat){return cat == "0" || cat == "none";})) {
for (const auto& cat : categories) { for (const auto& cat : categories) {
if (!g_logger->EnableCategory(cat)) { if (!LogInstance().EnableCategory(cat)) {
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
} }
} }
@ -1375,7 +1375,7 @@ bool AppInitParameterInteraction()
// Now remove the logging categories which were explicitly excluded // Now remove the logging categories which were explicitly excluded
for (const std::string& cat : gArgs.GetArgs("-debugexclude")) { for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
if (!g_logger->DisableCategory(cat)) { if (!LogInstance().DisableCategory(cat)) {
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
} }
} }
@ -1619,19 +1619,19 @@ bool AppInitMain()
return false; return false;
} }
#endif #endif
if (g_logger->m_print_to_file) { if (LogInstance().m_print_to_file) {
if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) { if (gArgs.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) {
// Do this first since it both loads a bunch of debug.log into memory, // Do this first since it both loads a bunch of debug.log into memory,
// and because this needs to happen before any other debug.log printing // and because this needs to happen before any other debug.log printing
g_logger->ShrinkDebugFile(); LogInstance().ShrinkDebugFile();
} }
} }
if (!g_logger->StartLogging()) { if (!LogInstance().StartLogging()) {
return InitError(strprintf("Could not open debug log file %s", return InitError(strprintf("Could not open debug log file %s",
g_logger->m_file_path.string())); LogInstance().m_file_path.string()));
} }
if (!g_logger->m_log_timestamps) if (!LogInstance().m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", GetDataDir().string()); LogPrintf("Using data directory %s\n", GetDataDir().string());

View File

@ -175,7 +175,7 @@ class NodeImpl : public Node
void initLogging() override { InitLogging(); } void initLogging() override { InitLogging(); }
void initParameterInteraction() override { InitParameterInteraction(); } void initParameterInteraction() override { InitParameterInteraction(); }
std::string getWarnings(const std::string& type) override { return GetWarnings(type); } std::string getWarnings(const std::string& type) override { return GetWarnings(type); }
uint64_t getLogCategories() override { return g_logger->GetCategoryMask(); } uint64_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override bool baseInitialize() override
{ {
return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() && return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&

View File

@ -24,7 +24,7 @@ CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const ui
} }
#define LogPrintfFinalCommitment(...) do { \ #define LogPrintfFinalCommitment(...) do { \
g_logger->LogPrintStr(strprintf("CFinalCommitment::%s -- %s", __func__, tinyformat::format(__VA_ARGS__))); \ LogInstance().LogPrintStr(strprintf("CFinalCommitment::%s -- %s", __func__, tinyformat::format(__VA_ARGS__))); \
} while(0) } while(0)
bool CFinalCommitment::Verify(const CBlockIndex* pQuorumIndex, bool checkSigs) const bool CFinalCommitment::Verify(const CBlockIndex* pQuorumIndex, bool checkSigs) const

View File

@ -12,6 +12,8 @@
const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
BCLog::Logger& LogInstance()
{
/** /**
* NOTE: the logger instances is leaked on exit. This is ugly, but will be * NOTE: the logger instances is leaked on exit. This is ugly, but will be
* cleaned up by the OS/libc. Defining a logger as a global object doesn't work * cleaned up by the OS/libc. Defining a logger as a global object doesn't work
@ -21,11 +23,15 @@ const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
* access the logger. When the shutdown sequence is fully audited and tested, * access the logger. When the shutdown sequence is fully audited and tested,
* explicit destruction of these objects can be implemented by changing this * explicit destruction of these objects can be implemented by changing this
* from a raw pointer to a std::unique_ptr. * from a raw pointer to a std::unique_ptr.
* Since the destructor is never called, the logger and all its members must
* have a trivial destructor.
* *
* This method of initialization was originally introduced in * This method of initialization was originally introduced in
* ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c. * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.
*/ */
BCLog::Logger* const g_logger = new BCLog::Logger(); static BCLog::Logger* g_logger{new BCLog::Logger()};
return *g_logger;
}
bool fLogIPs = DEFAULT_LOGIPS; bool fLogIPs = DEFAULT_LOGIPS;
@ -204,9 +210,9 @@ std::vector<CLogCategoryActive> ListActiveLogCategories()
std::string ListActiveLogCategoriesString() std::string ListActiveLogCategoriesString()
{ {
if (g_logger->GetCategoryMask() == BCLog::NONE) if (LogInstance().GetCategoryMask() == BCLog::NONE)
return "0"; return "0";
if (g_logger->GetCategoryMask() == BCLog::ALL) if (LogInstance().GetCategoryMask() == BCLog::ALL)
return "1"; return "1";
std::string ret; std::string ret;

View File

@ -142,12 +142,12 @@ namespace BCLog {
} // namespace BCLog } // namespace BCLog
extern BCLog::Logger* const g_logger; BCLog::Logger& LogInstance();
/** Return true if log accepts specified category */ /** Return true if log accepts specified category */
static inline bool LogAcceptCategory(BCLog::LogFlags category) static inline bool LogAcceptCategory(BCLog::LogFlags category)
{ {
return g_logger->WillLogCategory(category); return LogInstance().WillLogCategory(category);
} }
/** Returns a string with the log categories. */ /** Returns a string with the log categories. */
@ -182,7 +182,7 @@ std::string SafeStringFormat(const std::string& fmt, const Args&... args)
template <typename... Args> template <typename... Args>
static inline void LogPrintf(const char* fmt, const Args&... args) static inline void LogPrintf(const char* fmt, const Args&... args)
{ {
if (g_logger->Enabled()) { if (LogInstance().Enabled()) {
std::string log_msg; std::string log_msg;
try { try {
log_msg = tfm::format(fmt, args...); log_msg = tfm::format(fmt, args...);
@ -190,7 +190,7 @@ static inline void LogPrintf(const char* fmt, const Args&... args)
/* Original format string will have newline so don't add one here */ /* Original format string will have newline so don't add one here */
log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt; log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt;
} }
g_logger->LogPrintStr(log_msg); LogInstance().LogPrintStr(log_msg);
} }
} }

View File

@ -59,14 +59,14 @@ static UniValue debug(const JSONRPCRequest& request)
); );
std::string strMode = request.params[0].get_str(); std::string strMode = request.params[0].get_str();
g_logger->DisableCategory(BCLog::ALL); LogInstance().DisableCategory(BCLog::ALL);
std::vector<std::string> categories; std::vector<std::string> categories;
boost::split(categories, strMode, boost::is_any_of("+")); boost::split(categories, strMode, boost::is_any_of("+"));
if (std::find(categories.begin(), categories.end(), std::string("0")) == categories.end()) { if (std::find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {
for (const auto& cat : categories) { for (const auto& cat : categories) {
g_logger->EnableCategory(cat); LogInstance().EnableCategory(cat);
} }
} }
@ -1023,9 +1023,9 @@ static void EnableOrDisableLogCategories(UniValue cats, bool enable) {
bool success; bool success;
if (enable) { if (enable) {
success = g_logger->EnableCategory(cat); success = LogInstance().EnableCategory(cat);
} else { } else {
success = g_logger->DisableCategory(cat); success = LogInstance().DisableCategory(cat);
} }
if (!success) { if (!success) {
@ -1072,14 +1072,14 @@ static UniValue logging(const JSONRPCRequest& request)
); );
} }
uint64_t original_log_categories = g_logger->GetCategoryMask(); uint64_t original_log_categories = LogInstance().GetCategoryMask();
if (request.params[0].isArray()) { if (request.params[0].isArray()) {
EnableOrDisableLogCategories(request.params[0], true); EnableOrDisableLogCategories(request.params[0], true);
} }
if (request.params[1].isArray()) { if (request.params[1].isArray()) {
EnableOrDisableLogCategories(request.params[1], false); EnableOrDisableLogCategories(request.params[1], false);
} }
uint64_t updated_log_categories = g_logger->GetCategoryMask(); uint64_t updated_log_categories = LogInstance().GetCategoryMask();
uint64_t changed_log_categories = original_log_categories ^ updated_log_categories; uint64_t changed_log_categories = original_log_categories ^ updated_log_categories;
// Update libevent logging if BCLog::LIBEVENT has changed. // Update libevent logging if BCLog::LIBEVENT has changed.
@ -1088,8 +1088,8 @@ static UniValue logging(const JSONRPCRequest& request)
// Throw an error if the user has explicitly asked to change only the libevent // Throw an error if the user has explicitly asked to change only the libevent
// flag and it failed. // flag and it failed.
if (changed_log_categories & BCLog::LIBEVENT) { if (changed_log_categories & BCLog::LIBEVENT) {
if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
g_logger->DisableCategory(BCLog::LIBEVENT); LogInstance().DisableCategory(BCLog::LIBEVENT);
if (changed_log_categories == BCLog::LIBEVENT) { if (changed_log_categories == BCLog::LIBEVENT) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1."); throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
} }