summaryrefslogtreecommitdiff
path: root/src/mongo/unittest/death_test.cpp
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2020-07-02 20:04:31 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-03 00:31:10 +0000
commitbf36c726bd2befb026236b10c962e5cb55bceadc (patch)
tree038ca7a945c36b1fa7906cd39ae7ee3440554566 /src/mongo/unittest/death_test.cpp
parentbc470fa684619411b721d176f806ea8093a0c5f9 (diff)
downloadmongo-bf36c726bd2befb026236b10c962e5cb55bceadc.tar.gz
SERVER-48887 C++ death tests should fail on TSAN exit code
Diffstat (limited to 'src/mongo/unittest/death_test.cpp')
-rw-r--r--src/mongo/unittest/death_test.cpp27
1 files changed, 26 insertions, 1 deletions
diff --git a/src/mongo/unittest/death_test.cpp b/src/mongo/unittest/death_test.cpp
index 50ec0fda6db..3cba33b8ccd 100644
--- a/src/mongo/unittest/death_test.cpp
+++ b/src/mongo/unittest/death_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/bson/json.h"
#include "mongo/unittest/death_test.h"
+#include "mongo/util/exit_code.h"
#ifndef _WIN32
#include <cstdio>
@@ -47,6 +48,10 @@
#include <TargetConditionals.h>
#endif
+#if defined(__has_feature) && __has_feature(thread_sanitizer)
+#include <sanitizer/common_interface_defs.h>
+#endif
+
#include <sstream>
#include "mongo/logv2/log.h"
@@ -81,6 +86,15 @@ void logAndThrowWithErrnoAt(const StringData expr,
"{} failed: {} @{}:{}"_format(expr, errnoWithDescription(err), file, line));
}
+#if defined(__has_feature) && __has_feature(thread_sanitizer)
+// Our callback handler exits with the default TSAN exit code so we can check in the death test
+// framework Without this, the use could override the exit code and get a false positive that the
+// test passes in TSAN builds.
+void sanitizerDieCallback() {
+ _exit(EXIT_THREAD_SANITIZER);
+}
+#endif
+
void DeathTestBase::_doTest() {
#if defined(_WIN32)
LOGV2(24133, "Skipping death test on Windows");
@@ -150,7 +164,14 @@ void DeathTestBase::_doTest() {
}
}
if (WIFSIGNALED(stat) || (WIFEXITED(stat) && WEXITSTATUS(stat) != 0)) {
- // Exited with a signal or non-zero code. Validate the expected message.
+// Exited with a signal or non-zero code. Validate the expected message.
+#if defined(__has_feature) && __has_feature(thread_sanitizer)
+ if (WEXITSTATUS(stat) == EXIT_THREAD_SANITIZER) {
+ FAIL(
+ "Death test exited with Thread Sanitizer exit code, search test output for "
+ "'ThreadSanitizer' for more information");
+ }
+#endif
if (_isRegex()) {
ASSERT_STRING_SEARCH_REGEX(os.str(), _doGetPattern())
<< " @" << _getFile() << ":" << _getLine();
@@ -180,6 +201,10 @@ void DeathTestBase::_doTest() {
if (setrlimit(RLIMIT_CORE, &kNoCoreDump) == -1)
logAndThrowWithErrno("setrlimit(RLIMIT_CORE, &kNoCoreDump)");
+#if defined(__has_feature) && __has_feature(thread_sanitizer)
+ __sanitizer_set_death_callback(sanitizerDieCallback);
+#endif
+
try {
auto test = _doMakeTest();
LOGV2(23515, "Running DeathTest in child");