summaryrefslogtreecommitdiffstats
path: root/lldb/unittests/Core/LogTest.cpp
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2017-02-21 09:58:23 +0000
committerPavel Labath <labath@google.com>2017-02-21 09:58:23 +0000
commitba95a28c18e98c4e9017d9b9a8c36c20eb638d5a (patch)
treeda9ed8e691f5e228791eede9ccfe5e7ca599b5b3 /lldb/unittests/Core/LogTest.cpp
parent52a82e2ec6956e84fb52518b4077beb2fadd44b6 (diff)
downloadbcm5719-llvm-ba95a28c18e98c4e9017d9b9a8c36c20eb638d5a.tar.gz
bcm5719-llvm-ba95a28c18e98c4e9017d9b9a8c36c20eb638d5a.zip
Log: Fix race in accessing the stream variable
Summary: The code was attempting to copy the shared pointer member in order to guarantee atomicity, but this is not enough. Instead, protect the pointer with a proper read-write mutex. This bug was present here for a long time, but my recent refactors must have altered the timings slightly, such that now this fails fairly often when running the tests: the test runner runs the "log disable" command just as the thread monitoring the lldb-server child is about to report that the server has exited. I add a test case for this. It's not possible to reproduce the race deterministically in normal circumstances, but I have verified that before the fix, the test failed when run under tsan, and was running fine afterwards. Reviewers: clayborg, zturner Subscribers: lldb-commits Differential Revision: https://reviews.llvm.org/D30168 llvm-svn: 295712
Diffstat (limited to 'lldb/unittests/Core/LogTest.cpp')
-rw-r--r--lldb/unittests/Core/LogTest.cpp26
1 files changed, 26 insertions, 0 deletions
diff --git a/lldb/unittests/Core/LogTest.cpp b/lldb/unittests/Core/LogTest.cpp
index f93b9f21b3e..0b9ed00bbba 100644
--- a/lldb/unittests/Core/LogTest.cpp
+++ b/lldb/unittests/Core/LogTest.cpp
@@ -13,6 +13,7 @@
#include "lldb/Host/Host.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/Support/ManagedStatic.h"
+#include <thread>
using namespace lldb;
using namespace lldb_private;
@@ -26,6 +27,8 @@ static constexpr uint32_t default_flags = FOO;
static Log::Channel test_channel(test_categories, default_flags);
struct LogChannelTest : public ::testing::Test {
+ void TearDown() override { Log::DisableAllLogChannels(nullptr); }
+
static void SetUpTestCase() {
Log::Register("chan", test_channel);
}
@@ -170,3 +173,26 @@ TEST_F(LogChannelTest, List) {
EXPECT_FALSE(Log::ListChannelCategories("chanchan", str));
EXPECT_EQ("Invalid log channel 'chanchan'.\n", str.GetString().str());
}
+
+TEST_F(LogChannelTest, LogThread) {
+ // Test that we are able to concurrently write to a log channel and disable
+ // it.
+ std::string message;
+ std::shared_ptr<llvm::raw_string_ostream> stream_sp(
+ new llvm::raw_string_ostream(message));
+ StreamString err;
+ EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", nullptr, err));
+
+ Log *log = test_channel.GetLogIfAll(FOO);
+
+ // Start logging on one thread. Concurrently, try disabling the log channel.
+ std::thread log_thread([log] { LLDB_LOG(log, "Hello World"); });
+ EXPECT_TRUE(Log::DisableLogChannel("chan", nullptr, err));
+ log_thread.join();
+
+ // The log thread either managed to write to the log in time, or it didn't. In
+ // either case, we should not trip any undefined behavior (run the test under
+ // TSAN to verify this).
+ EXPECT_TRUE(stream_sp->str() == "" || stream_sp->str() == "Hello World\n")
+ << "str(): " << stream_sp->str();
+}
OpenPOWER on IntegriCloud