diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2019-10-28 18:45:44 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-10-28 18:45:44 +0000 |
commit | 4cd64d4068208811332845b4f02ffd83a08ad9ac (patch) | |
tree | a3f6c6edb303d6cbd19dc8d14fa9b1d98a33cb58 /src/mongo | |
parent | 46983435148b982ed73b06f88c3a1156526d0d9c (diff) | |
download | mongo-4cd64d4068208811332845b4f02ffd83a08ad9ac.tar.gz |
SERVER-44117 early stacktrace processInfo
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/util/stacktrace_posix.cpp | 5 | ||||
-rw-r--r-- | src/mongo/util/stacktrace_somap.cpp | 44 | ||||
-rw-r--r-- | src/mongo/util/stacktrace_somap.h | 12 | ||||
-rw-r--r-- | src/mongo/util/stacktrace_test.cpp | 36 |
4 files changed, 77 insertions, 20 deletions
diff --git a/src/mongo/util/stacktrace_posix.cpp b/src/mongo/util/stacktrace_posix.cpp index a975f869feb..c24fb71e092 100644 --- a/src/mongo/util/stacktrace_posix.cpp +++ b/src/mongo/util/stacktrace_posix.cpp @@ -253,10 +253,7 @@ void appendJsonProcessInfo(IterationIface& source, const StackTraceOptions& options) { if (!options.withProcessInfo) return; - auto bsonSoMap = globalSharedObjectMapInfo(); - if (!bsonSoMap) - return; - const BSONObj& bsonProcInfo = bsonSoMap->obj(); + const BSONObj& bsonProcInfo = globalSharedObjectMapInfo().obj(); CheapJson::Value jsonProcInfo = jsonRoot.appendKey("processInfo").appendObj(); if (options.trimSoMap) { printJsonProcessInfoTrimmed(source, bsonProcInfo, jsonProcInfo); diff --git a/src/mongo/util/stacktrace_somap.cpp b/src/mongo/util/stacktrace_somap.cpp index 75ccf94eb63..893df5b7744 100644 --- a/src/mongo/util/stacktrace_somap.cpp +++ b/src/mongo/util/stacktrace_somap.cpp @@ -306,32 +306,54 @@ void addOSComponentsToSoMap(BSONObjBuilder* soMap) {} #endif // unknown OS -SharedObjectMapInfo* _globalSharedObjectMapInfo = nullptr; - /** - * Builds the "soMapJson" string, which is a JSON encoding of various pieces of information - * about a running process, including the map from load addresses to shared objects loaded at - * those addresses. + * Used to build the "processInfo" field of the stacktrace JSON object. It's loaded with + * information about a running process, including the map from load addresses to shared + * objects loaded at those addresses. */ -MONGO_INITIALIZER(ExtractSOMap)(InitializerContext*) { +BSONObj buildObj() { BSONObjBuilder soMap; - auto&& vii = VersionInfoInterface::instance(VersionInfoInterface::NotEnabledAction::kFallback); soMap << "mongodbVersion" << vii.version(); soMap << "gitVersion" << vii.gitVersion(); soMap << "compiledModules" << vii.modules(); - addOSComponentsToSoMap(&soMap); - _globalSharedObjectMapInfo = new SharedObjectMapInfo(soMap.obj()); + return soMap.obj(); +} + +SharedObjectMapInfo& mutableGlobalSharedObjectMapInfo() { + auto& p = *new SharedObjectMapInfo(buildObj()); + return p; +} + +MONGO_INITIALIZER(ExtractSOMap)(InitializerContext*) { + // Call buildObj() again now that there is better VersionInfo. + mutableGlobalSharedObjectMapInfo().setObj(buildObj()); return Status::OK(); } +const bool dummyToForceEarlyInitializationOfSharedObjectMapInfo = [] { + mutableGlobalSharedObjectMapInfo(); + return true; +}(); + } // namespace SharedObjectMapInfo::SharedObjectMapInfo(BSONObj obj) : _obj(std::move(obj)) {} -SharedObjectMapInfo* globalSharedObjectMapInfo() { - return _globalSharedObjectMapInfo; +const BSONObj& SharedObjectMapInfo::obj() const { + return _obj; +} + +void SharedObjectMapInfo::setObj(BSONObj obj) { + _obj = std::move(obj); +} + +const SharedObjectMapInfo& globalSharedObjectMapInfo() { + // This file internally has a non-const object, but only exposes a const reference + // to it to the public API. We do this to support stacktraces that might occur + // before the "ExtractSOMap" MONGO_INITIALIZER above. + return mutableGlobalSharedObjectMapInfo(); } } // namespace mongo diff --git a/src/mongo/util/stacktrace_somap.h b/src/mongo/util/stacktrace_somap.h index 9e2db532cc8..a689fef4714 100644 --- a/src/mongo/util/stacktrace_somap.h +++ b/src/mongo/util/stacktrace_somap.h @@ -37,15 +37,17 @@ namespace mongo { class SharedObjectMapInfo { public: explicit SharedObjectMapInfo(BSONObj obj); - const BSONObj& obj() const { - return _obj; - } + + const BSONObj& obj() const; + + void setObj(BSONObj obj); private: BSONObj _obj; }; -// Available after the MONGO_INITIALIZER has run. -SharedObjectMapInfo* globalSharedObjectMapInfo(); +// Can always be called, but more information is populated +// after the MONGO_INITIALIZER has run. +const SharedObjectMapInfo& globalSharedObjectMapInfo(); } // namespace mongo diff --git a/src/mongo/util/stacktrace_test.cpp b/src/mongo/util/stacktrace_test.cpp index ee8d510cdec..3e1c47d3ade 100644 --- a/src/mongo/util/stacktrace_test.cpp +++ b/src/mongo/util/stacktrace_test.cpp @@ -358,6 +358,42 @@ TEST(StackTrace, WindowsFormat) { << "of trace: `" << trace << "`"; } +std::string traceString() { + std::ostringstream os; + printStackTrace(os); + return os.str(); +} + +/** Emit a stack trace before main() runs, for use in the EarlyTraceSanity test. */ +std::string earlyTrace = traceString(); + +/** + * Verify that the JSON object emitted as part of a stack trace contains a "processInfo" + * field, and that it, in turn, contains the fields expected by mongosymb.py. Verify in + * particular that a stack trace emitted before main() and before the MONGO_INITIALIZERS + * have run will be valid according to mongosymb.py. + */ +TEST(StackTrace, EarlyTraceSanity) { + if (kIsWindows) { + return; + } + + const std::string trace = traceString(); + const std::string substrings[] = { + R"("processInfo":)", + R"("gitVersion":)", + R"("compiledModules":)", + R"("uname":)", + R"("somap":)", + }; + for (const auto& sub : substrings) { + ASSERT_STRING_CONTAINS(earlyTrace, sub); + } + for (const auto& sub : substrings) { + ASSERT_STRING_CONTAINS(trace, sub); + } +} + class StringSink : public StackTraceSink { public: StringSink(std::string& s) : _s{s} {} |