diff options
| author | Pavel Labath <labath@google.com> | 2017-02-21 09:58:23 +0000 |
|---|---|---|
| committer | Pavel Labath <labath@google.com> | 2017-02-21 09:58:23 +0000 |
| commit | ba95a28c18e98c4e9017d9b9a8c36c20eb638d5a (patch) | |
| tree | da9ed8e691f5e228791eede9ccfe5e7ca599b5b3 /lldb/unittests/Core/LogTest.cpp | |
| parent | 52a82e2ec6956e84fb52518b4077beb2fadd44b6 (diff) | |
| download | bcm5719-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.cpp | 26 |
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(); +} |

