summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorRyan Egesdahl <ryan.egesdahl@mongodb.com>2020-06-04 16:06:42 -0700
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-06-11 15:56:47 +0000
commitc7115a2c310b1645f6268007e3d458300dab6b54 (patch)
tree139caff20d6e7f2b2253b812e760beff442a8cc0 /src/mongo
parent0f707044926e0cec422294520f9e42d777818b1f (diff)
downloadmongo-c7115a2c310b1645f6268007e3d458300dab6b54.tar.gz
SERVER-48597 Fix stack trace unit tests with TSAN
Stack trace unit tests were failing with TSAN due to the mechanisms and assumptions of the tests. In one case, we simulate a real failure and do some thread necromancy to recover from it, which was causing TSAN to segfault immediately. In another two, we rely on a feature that makes some assumptions about which threads are running and what signals they can receive, which TSAN's internal threads violate. These tests and features are disabled with TSAN for now so we can run further tests with TSAN. Separately, one of the tests was failing with a complaint from TSAN that errno was being stomped on. That is also addressed.
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/stdx/sigaltstack_location_test.cpp9
-rw-r--r--src/mongo/util/stacktrace.h16
-rw-r--r--src/mongo/util/stacktrace_threads.cpp4
3 files changed, 26 insertions, 3 deletions
diff --git a/src/mongo/stdx/sigaltstack_location_test.cpp b/src/mongo/stdx/sigaltstack_location_test.cpp
index f6e37b94cc2..bfc0aba4393 100644
--- a/src/mongo/stdx/sigaltstack_location_test.cpp
+++ b/src/mongo/stdx/sigaltstack_location_test.cpp
@@ -256,8 +256,13 @@ int runTests() {
int (*func)();
} static constexpr kTests[] = {
{"stackLocationTest", &stackLocationTest},
-// These tests violate the memory space deliberately, so they generate false positives from ASAN.
-#if !__has_feature(address_sanitizer)
+// These tests violate the memory space deliberately, so they generate false
+// positives from ASAN. TSAN also fails because we rescue a thread from a
+// SIGSEGV due to intentional thread exhaustion with creative use of a longjmp.
+// TSAN is more clever than we want here and intercepts the SIGSEGV before we
+// can do the thread necromancy that lets us verify it died for the right reasons
+// without killing the test harness.
+#if !__has_feature(address_sanitizer) && !__has_feature(thread_sanitizer)
{"recursionTest", &recursionTest},
{"recursionDeathTest", &recursionDeathTest},
#endif
diff --git a/src/mongo/util/stacktrace.h b/src/mongo/util/stacktrace.h
index e36a0aea03b..4cc1ed688b6 100644
--- a/src/mongo/util/stacktrace.h
+++ b/src/mongo/util/stacktrace.h
@@ -40,6 +40,10 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/config.h"
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+
/**
* All-thread backtrace is only implemented on Linux. Even on Linux, it's only AS-safe
* when we are using the libunwind backtrace implementation. The feature and related
@@ -47,10 +51,20 @@
* - setupStackTraceSignalAction
* - markAsStackTraceProcessingThread
* - printAllThreadStacks
+ *
+ * This feature currently does not work with TSAN because TSAN introduces internal
+ * threads which block SIGUSR2, and that violates our assumption that all threads
+ * are known and accept SIGUSR2. With this enabled, users could try getting a
+ * stack trace and get a segfault instead. For the time being, we are disabling
+ * this feature with TSAN. However, this feature will need to be fixed to work with
+ * TSAN so developers can diagnose TSAN test failures with on-demand stack traces.
+ * TODO: https://jira.mongodb.org/browse/SERVER-48622
*/
-#if defined(__linux__) && defined(MONGO_CONFIG_USE_LIBUNWIND)
+#if defined(__linux__)
+#if defined(MONGO_CONFIG_USE_LIBUNWIND) && !__has_feature(thread_sanitizer)
#define MONGO_STACKTRACE_CAN_DUMP_ALL_THREADS
#endif
+#endif
namespace mongo {
diff --git a/src/mongo/util/stacktrace_threads.cpp b/src/mongo/util/stacktrace_threads.cpp
index 9f8dd99a1b9..05d6bcacb0d 100644
--- a/src/mongo/util/stacktrace_threads.cpp
+++ b/src/mongo/util/stacktrace_threads.cpp
@@ -616,6 +616,7 @@ void State::printToEmitter(AbstractEmitter& emitter) {
}
void State::action(siginfo_t* si) {
+ const auto errnoGuard = makeGuard([e = errno] { errno = e; });
switch (si->si_code) {
case SI_USER:
case SI_QUEUE:
@@ -647,6 +648,9 @@ void initialize(int signal) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
+ // We should never need to add to this lambda because it simply sets up handler
+ // execution. Any changes should either be in State::action or in the signal
+ // handler itself.
sa.sa_sigaction = [](int, siginfo_t* si, void*) { stateSingleton->action(si); };
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
if (sigaction(signal, &sa, nullptr) != 0) {