Add a basic TSan test for ref-counts. Confirmed that, if the locks are commented out, TSan catches the threading error. Change-Id: I3e4ef9a7ca85fdbacf8c8b13694a5a54c6d5f99b Reviewed-on: https://boringssl-review.googlesource.com/29924 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt index f58a7bb..104e50c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -268,6 +268,16 @@ set(OPENSSL_NO_ASM "1") endif() +if(TSAN) + if(NOT CLANG) + message(FATAL_ERROR "Cannot enable TSAN unless using Clang") + endif() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") +endif() + if (GCOV) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
diff --git a/crypto/refcount_test.cc b/crypto/refcount_test.cc index efa501a..6ce0746 100644 --- a/crypto/refcount_test.cc +++ b/crypto/refcount_test.cc
@@ -16,6 +16,10 @@ #include <gtest/gtest.h> +#if !defined(OPENSSL_NO_THREADS) +#include <thread> +#endif + TEST(RefCountTest, Basic) { CRYPTO_refcount_t count = 0; @@ -38,3 +42,38 @@ EXPECT_FALSE(CRYPTO_refcount_dec_and_test_zero(&count)); EXPECT_EQ(1u, count); } + +#if !defined(OPENSSL_NO_THREADS) +// This test is primarily intended to run under ThreadSanitizer. +TEST(RefCountTest, Threads) { + CRYPTO_refcount_t count = 0; + + // Race two increments. + { + std::thread thread([&] { CRYPTO_refcount_inc(&count); }); + CRYPTO_refcount_inc(&count); + thread.join(); + EXPECT_EQ(2u, count); + } + + // Race an increment with a decrement. + { + std::thread thread([&] { CRYPTO_refcount_inc(&count); }); + EXPECT_FALSE(CRYPTO_refcount_dec_and_test_zero(&count)); + thread.join(); + EXPECT_EQ(2u, count); + } + + // Race two decrements. + { + bool thread_saw_zero; + std::thread thread( + [&] { thread_saw_zero = CRYPTO_refcount_dec_and_test_zero(&count); }); + bool saw_zero = CRYPTO_refcount_dec_and_test_zero(&count); + thread.join(); + EXPECT_EQ(0u, count); + // Exactly one thread should see zero. + EXPECT_NE(saw_zero, thread_saw_zero); + } +} +#endif