summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2019-10-28 18:45:44 +0000
committerevergreen <evergreen@mongodb.com>2019-10-28 18:45:44 +0000
commit4cd64d4068208811332845b4f02ffd83a08ad9ac (patch)
treea3f6c6edb303d6cbd19dc8d14fa9b1d98a33cb58 /src/mongo
parent46983435148b982ed73b06f88c3a1156526d0d9c (diff)
downloadmongo-4cd64d4068208811332845b4f02ffd83a08ad9ac.tar.gz
SERVER-44117 early stacktrace processInfo
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/util/stacktrace_posix.cpp5
-rw-r--r--src/mongo/util/stacktrace_somap.cpp44
-rw-r--r--src/mongo/util/stacktrace_somap.h12
-rw-r--r--src/mongo/util/stacktrace_test.cpp36
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} {}